summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
1312 files changed, 165975 insertions, 0 deletions
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/
+}