diff --git a/doc/src/qtcreator.qdoc b/doc/src/qtcreator.qdoc index 667895cd800559c0c03d3d40a58ccf808811e262..82fd31ea065af2bac56a6032d899bffe3e0dec60 100644 --- a/doc/src/qtcreator.qdoc +++ b/doc/src/qtcreator.qdoc @@ -1,3 +1,4 @@ + /**************************************************************************** ** ** This file is part of Qt Creator @@ -44,31 +45,38 @@ \o \inlineimage creator_managingprojects.png \o \inlineimage creator_designinguserinterface.png \row - \o \bold {\l{Getting Started}} + \o \list + \o \bold {\l{Getting Started}} \list \o \l{IDE Overview} \o \l{User Interface} \o \l{Building and Running an Example} \o \l{Tutorials} \endlist - \o \bold {\l{Managing Projects}} + \endlist + \o \list + \o \bold {\l{Managing Projects}} \list \o \l{Creating Projects} \o \l{Using Version Control Systems} \o \l{Configuring Projects} \o \l{Managing Sessions} \endlist + \endlist + \o \list \o \bold {\l{Designing User Interfaces}} \list \o \l{Developing Qt Quick Applications} \o \l{Developing Widget Based Applications} \o \l{Optimizing Applications for Mobile Devices} \endlist + \endlist \row \o \inlineimage creator_coding.png \o \inlineimage creator_buildingrunning.png \o \inlineimage creator_testing.png \row + \o \list \o \bold {\l{Coding}} \list \o \l{Writing Code} @@ -76,6 +84,8 @@ \o \l{Refactoring} \o \l{Configuring the Editor} \endlist + \endlist + \o \list \o \bold {\l{Building and Running}} \list \o \l{Building for Multiple Targets} @@ -83,16 +93,20 @@ \o \l{Deploying to Mobile Devices} \o \l{Connecting Mobile Targets} \endlist + \endlist + \o \list \o \bold {\l{Debugging and Analyzing}} \list \o \l{Debugging} \o \l{Analyzing Code} \endlist + \endlist \row \o \inlineimage creator_publishing.png \o \inlineimage creator_advanceduse.png \o \inlineimage creator_gettinghelp.png \row + \o \list \o \bold {\l{Publishing}} \list \o \l{Publishing Qt Content for Symbian Devices} @@ -100,6 +114,8 @@ \o \l{Publishing Qt Content for Maemo Devices} \o \l{Publishing Maemo Applications to Extras-devel} \endlist + \endlist + \o \list \o \bold {\l{Advanced Use}} \list \o \l{Supported Platforms} @@ -108,6 +124,8 @@ \o \l{Keyboard Shortcuts} \o \l{Using External Tools} \endlist + \endlist + \o \list \o \bold {\l{Getting Help}} \list \o \l{Using the Help Mode} @@ -116,6 +134,7 @@ \o \l{Known Issues} \o \l{Glossary} \endlist + \endlist \row \o {3,1} \note To report bugs and suggestions to the Qt Bug Tracker, select \gui {Help > Report Bug}. @@ -125,6 +144,7 @@ {lists.qt-project.org Mailing Lists}. \endtable + \omit \section1 Table Of Contents \list @@ -289,4 +309,5 @@ \o \l{Acknowledgements} \endlist \endlist + \endomit */ diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 8efb360ea99ff97adabd44360d6d33f29a18fd21..65c9f5929245b817a3a29103e924311abb9feaf2 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -1428,8 +1428,6 @@ void ProjectExplorerPlugin::currentModeChanged(Core::IMode *mode, Core::IMode *o { if (mode && mode->id() == Core::Id(Core::Constants::MODE_WELCOME).toString()) updateWelcomePage(); - if (oldMode == d->m_projectsMode) - savePersistentSettings(); } void ProjectExplorerPlugin::determineSessionToRestoreAtStartup() diff --git a/tests/system/objects.map b/tests/system/objects.map index 7345a42fb2dab2d40d9536dd55e623d70eb489c5..2f228d6fd4ed13413acfa86d05fd6929eb4b7be0 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -1,5 +1,8 @@ :*Qt Creator.Build Project_Core::Internal::FancyToolButton {text='Build Project' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} +:*Qt Creator.Continue_Core::Internal::FancyToolButton {text='Continue' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} +:*Qt Creator.Interrupt_Core::Internal::FancyToolButton {text='Interrupt' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator.Run_Core::Internal::FancyToolButton {text='Run' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} +:*Qt Creator.Start Debugging_Core::Internal::FancyToolButton {text='Start Debugging' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator.findEdit_Utils::FilterLineEdit {name='findEdit' type='Utils::FilterLineEdit' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator.qt_tabwidget_stackedwidget_QStackedWidget {name='qt_tabwidget_stackedwidget' type='QStackedWidget' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :*Qt Creator_Core::Internal::FancyToolButton {occurrence='3' type='Core::Internal::FancyToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} @@ -12,6 +15,12 @@ :CMake Wizard.Run CMake_QPushButton {text='Run CMake' type='QPushButton' unnamed='1' visible='1' window=':CMake Wizard_CMakeProjectManager::Internal::CMakeOpenProjectWizard'} :CMake Wizard_CMakeProjectManager::Internal::CMakeOpenProjectWizard {type='CMakeProjectManager::Internal::CMakeOpenProjectWizard' unnamed='1' visible='1' windowTitle='CMake Wizard'} :DebugModeWidget.Debugger Log_QDockWidget {container=':Qt Creator.DebugModeWidget_QSplitter' name='Debugger.Docks.Output' type='QDockWidget' visible='1' windowTitle='Debugger Log'} +:DebugModeWidget.Debugger Toolbar_QDockWidget {container=':Qt Creator.DebugModeWidget_QSplitter' name='Debugger Toolbar' type='QDockWidget' visible='1' windowTitle='Debugger Toolbar'} +:DebugModeWidget.OK_QPushButton {container=':Qt Creator.DebugModeWidget_QSplitter' text='OK' type='QPushButton' unnamed='1' visible='1'} +:Debugger Toolbar.Continue_QToolButton {container=':DebugModeWidget.Debugger Toolbar_QDockWidget' text='Continue' type='QToolButton' unnamed='1' visible='1'} +:Debugger Toolbar.Exit Debugger_QToolButton {container=':DebugModeWidget.Debugger Toolbar_QDockWidget' text='Exit Debugger' type='QToolButton' unnamed='1' visible='1'} +:Debugger Toolbar.StatusText_Utils::StatusLabel {container=':DebugModeWidget.Debugger Toolbar_QDockWidget' type='Utils::StatusLabel' unnamed='1'} +:Failed to start application_QMessageBox {type='QMessageBox' unnamed='1' visible='1' windowTitle='Failed to start application'} :Generator:_QComboBox {buddy=':CMake Wizard.Generator:_QLabel' type='QComboBox' unnamed='1' visible='1'} :New.frame_QFrame {name='frame' type='QFrame' visible='1' window=':New_Core::Internal::NewDialog'} :New.templateCategoryView_QTreeView {name='templateCategoryView' type='QTreeView' visible='1' window=':New_Core::Internal::NewDialog'} @@ -57,6 +66,7 @@ :qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget {container=':Options.qt_tabwidget_stackedwidget_QStackedWidget' name='QtSupport__Internal__QtVersionManager' type='QtSupport::Internal::QtOptionsPageWidget' visible='1'} :scrollArea.Create Build Configurations:_QComboBox_2 {container=':Qt Gui Application.scrollArea_QScrollArea' leftWidget=':scrollArea.Create Build Configurations:_QLabel_2' type='QComboBox' unnamed='1' visible='1'} :scrollArea.Create Build Configurations:_QLabel_2 {container=':Qt Gui Application.scrollArea_QScrollArea' text='Create build configurations:' type='QLabel' unnamed='1' visible='1'} +:scrollArea.Details_Utils::DetailsButton {container=':Qt Creator.scrollArea_QScrollArea' text='Details' type='Utils::DetailsButton' unnamed='1' visible='1'} :scrollArea.Edit build configuration:_QComboBox {container=':Qt Creator.scrollArea_QScrollArea' leftWidget=':scrollArea.Edit build configuration:_QLabel' type='QComboBox' unnamed='1' visible='1'} :scrollArea.Edit build configuration:_QLabel {container=':Qt Creator.scrollArea_QScrollArea' text='Edit build configuration:' type='QLabel' unnamed='1' visible='1'} :scrollArea.Qt 4 for Desktop - (Qt SDK) debug_QCheckBox {container=':Qt Gui Application.scrollArea_QScrollArea' text?='*Qt 4.* for *(Qt SDK) debug' type='QCheckBox' unnamed='1' visible='1'} diff --git a/tests/system/shared/build_utils.py b/tests/system/shared/build_utils.py index ed39e0606906c530f8fd16b60fb25a859def0569..156cdad1a7037076ca489e2442a05f07caf980d0 100644 --- a/tests/system/shared/build_utils.py +++ b/tests/system/shared/build_utils.py @@ -163,3 +163,25 @@ def selectBuildConfig(targetCount, currentTarget, configName): waitForSignal("{type='CppTools::Internal::CppModelManager' unnamed='1'}", "sourceFilesRefreshed(QStringList)") switchViewTo(ViewConstants.EDIT) + +def verifyBuildConfig(targetCount, currentTarget, shouldBeDebug=False, enableShadowBuild=False): + switchViewTo(ViewConstants.PROJECTS) + switchToBuildOrRunSettingsFor(targetCount, currentTarget, ProjectSettings.BUILD) + detailsButton = waitForObject(":scrollArea.Details_Utils::DetailsButton") + ensureChecked(detailsButton) + ensureChecked("{name='shadowBuildCheckBox' type='QCheckBox' visible='1'}", enableShadowBuild) + buildCfCombo = waitForObject("{type='QComboBox' name='buildConfigurationComboBox' visible='1' " + "container=':Qt Creator.scrollArea_QScrollArea'}") + if shouldBeDebug: + test.compare(buildCfCombo.currentText, 'Debug', "Verifying whether it's a debug build") + else: + test.compare(buildCfCombo.currentText, 'Release', "Verifying whether it's a release build") + try: + problemFound = waitForObject("{container=':Qt Creator.scrollArea_QScrollArea' type='QLabel' " + "name='problemLabel' visible='1'}", 1000) + if problemFound: + test.warning('%s' % problemFound.text) + except: + pass + clickButton(detailsButton) + switchViewTo(ViewConstants.EDIT) diff --git a/tests/system/shared/debugger.py b/tests/system/shared/debugger.py index 6ddb2a68eebb87684319e23af667b06437539a0f..42957d8d246f2069649f935a387144e60e3ce180 100644 --- a/tests/system/shared/debugger.py +++ b/tests/system/shared/debugger.py @@ -1,3 +1,5 @@ +import re + def handleDebuggerWarnings(config): if "MSVC" in config: try: @@ -31,3 +33,187 @@ def takeDebuggerLog(): waitFor("str(debuggerLogWindow.plainText)==''", 5000) invokeMenuItem("Window", "Views", "Debugger Log") return debuggerLog + +# function to set breakpoints for the current project +# on the given file,line pairs inside the given dict +# the lines are treated as regular expression +def setBreakpointsForCurrentProject(filesAndLines): + # internal helper for setBreakpointsForCurrentProject + # double clicks the treeElement inside the given navTree + # TODO: merge with doubleClickFile() from tst_qml_editor & move to utils(?) + def __doubleClickFile__(navTree, treeElement): + waitForObjectItem(navTree, treeElement) + fileNamePattern = re.compile(".*\.(?P<file>(.*\\\..*)?)$") + fileName = fileNamePattern.search(treeElement).group("file").replace("\\.", ".") + doubleClickItem(navTree, treeElement, 5, 5, 0, Qt.LeftButton) + mainWindow = waitForObject(":Qt Creator_Core::Internal::MainWindow") + waitFor('fileName in str(mainWindow.windowTitle)', 5000) + return fileName + + switchViewTo(ViewConstants.DEBUG) + removeOldBreakpoints() + if not filesAndLines or not isinstance(filesAndLines, dict): + test.fatal("This function only takes a non-empty dict.") + return False + navTree = waitForObject("{type='Utils::NavigationTreeView' unnamed='1' visible='1' " + "window=':Qt Creator_Core::Internal::MainWindow'}", 20000) + for curFile,curLine in filesAndLines.iteritems(): + fName = __doubleClickFile__(navTree, curFile) + editor = getEditorForFileSuffix(curFile) + if not placeCursorToLine(editor, curLine, True): + return False + invokeMenuItem("Debug", "Toggle Breakpoint") + test.log('Set breakpoint in %s' % fName, curLine) + breakPointTreeView = waitForObject("{type='Debugger::Internal::BreakWindow' visible='1' " + "windowTitle='Breakpoints' name='Debugger.Docks.Break'}") + waitFor("breakPointTreeView.model().rowCount() == len(filesAndLines)", 2000) + test.compare(breakPointTreeView.model().rowCount(), len(filesAndLines), + 'Expected %d set break points, found %d listed' % + (len(filesAndLines), breakPointTreeView.model().rowCount())) + return True + +# helper that removes all breakpoints - assumes that it's getting called +# being already on Debug view and Breakpoints widget is not disabled +def removeOldBreakpoints(): + test.log("Removing old breakpoints if there are any") + try: + breakPointTreeView = waitForObject("{type='Debugger::Internal::BreakWindow' visible='1' " + "windowTitle='Breakpoints' name='Debugger.Docks.Break'}") + model = breakPointTreeView.model() + if model.rowCount()==0: + test.log("No breakpoints found...") + else: + test.log("Found %d breakpoints - removing them" % model.rowCount()) + for row in range(model.rowCount()): + currentIndex = model.index(row,0) + rect = breakPointTreeView.visualRect(currentIndex) + mouseClick(breakPointTreeView, rect.x+5, rect.y+5, 0, Qt.LeftButton) + type(breakPointTreeView, "<Delete>") + except LookupError: + pass + return test.compare(model.rowCount(), 0, "Check if all breakpoints have been removed.") + +# function to do simple debugging of the current (configured) project +# param pressContinueCount defines how often it is expected to press +# the 'Continue' button while debugging +# param expectedBPOrder holds a list of dicts where the dicts contain always +# only 1 key:value pair - the key is the name of the file, the value is +# line number where the debugger should stop +def doSimpleDebugging(currentConfigName, pressContinueCount=1, expectedBPOrder=[]): + expectedLabelTexts = ['Stopped\.', 'Stopped at breakpoint \d+ \(\d+\) in thread \d+\.'] + if len(expectedBPOrder) == 0: + expectedLabelTexts.append("Running\.") + if not __startDebugger__(currentConfigName): + return False + statusLabel = findObject(":Debugger Toolbar.StatusText_Utils::StatusLabel") + test.log("Continuing debugging %d times..." % pressContinueCount) + for i in range(pressContinueCount): + if waitFor("regexVerify(str(statusLabel.text), expectedLabelTexts)", 20000): + verifyBreakPoint(expectedBPOrder[i]) + else: + test.fail('%s' % str(statusLabel.text)) + contDbg = waitForObject(":*Qt Creator.Continue_Core::Internal::FancyToolButton", 3000) + test.log("Continuing...") + clickButton(contDbg) + waitFor("str(statusLabel.text) == 'Running.'", 5000) + timedOut = not waitFor("str(statusLabel.text) in ['Running.', 'Debugger finished.']", 30000) + if timedOut: + test.log("Waiting for 'Running.' / 'Debugger finished.' timed out.", + "Debugger is in state: '%s'..." % statusLabel.text) + if str(statusLabel.text) == 'Running.': + test.log("Debugger is still running... Will be stopped.") + return __stopDebugger__() + elif str(statusLabel.text) == 'Debugger finished.': + test.log("Debugger has finished.") + return __logDebugResult__() + else: + test.log("Trying to stop debugger...") + try: + return __stopDebugger__() + except: + # if stopping failed - debugger had already stopped + return True + +def __startDebugger__(config): + clickButton(waitForObject(":*Qt Creator.Start Debugging_Core::Internal::FancyToolButton")) + handleDebuggerWarnings(config) + hasNotTimedOut = waitFor("object.exists(':Debugger Toolbar.Continue_QToolButton')", 20000) + try: + mBox = findObject(":Failed to start application_QMessageBox") + mBoxText = mBox.text + mBoxIText = mBox.informativeText + clickButton(":DebugModeWidget.OK_QPushButton") + test.fail("Debugger hasn't started... QMessageBox appeared!") + test.log("QMessageBox content: '%s'" % mBoxText, + "'%s'" % mBoxIText) + return False + except: + pass + if hasNotTimedOut: + test.passes("Debugger started...") + else: + test.fail("Debugger seems to have not started...") + if "MSVC" in config: + debuggerLog = takeDebuggerLog() + if "lib\qtcreatorcdbext64\qtcreatorcdbext.dll cannot be found." in debuggerLog: + test.fatal("qtcreatorcdbext.dll is missing in lib\qtcreatorcdbext64") + else: + test.fatal("Debugger log did not behave as expected. Please check manually.") + logApplicationOutput() + return False + try: + waitForObject(":*Qt Creator.Interrupt_Core::Internal::FancyToolButton", 3000) + test.passes("'Interrupt' (debugger) button visible.") + except: + try: + waitForObject(":*Qt Creator.Continue_Core::Internal::FancyToolButton", 3000) + test.passes("'Continue' (debugger) button visible.") + except: + test.fatal("Neither 'Interrupt' nor 'Continue' button visible (Debugger).") + return True + +def __stopDebugger__(): + clickButton(waitForObject(":Debugger Toolbar.Exit Debugger_QToolButton")) + ensureChecked("{type='Core::Internal::OutputPaneToggleButton' unnamed='1' visible='1' " + "window=':Qt Creator_Core::Internal::MainWindow' occurrence='3'}") + output = waitForObject("{type='Core::OutputWindow' visible='1' windowTitle='Application Output Window'}", 20000) + waitFor("'Debugging has finished' in str(output.plainText)", 20000) + return __logDebugResult__() + +def __logDebugResult__(): + try: + result = waitForObject(":*Qt Creator.Start Debugging_Core::Internal::FancyToolButton") + test.passes("'Start Debugging' button visible.") + except: + test.fail("'Start Debugging' button is not visible.") + result = None + if result: + test.passes("Debugger stopped.. Qt Creator is back at normal state.") + else: + test.fail("Debugger seems to have not stopped...") + logApplicationOutput() + return result + +def verifyBreakPoint(bpToVerify): + if isinstance(bpToVerify, dict): + fileName = bpToVerify.keys()[0] + editor = getEditorForFileSuffix(fileName) + if editor == None: + return False + textPos = editor.textCursor().position() + line = str(editor.plainText)[:textPos].count("\n") + 1 + windowTitle = str(waitForObject(":Qt Creator_Core::Internal::MainWindow").windowTitle) + if fileName in windowTitle: + test.passes("Creator's window title changed according to current file") + else: + test.fail("Creator's window title did not change according to current file") + if line == bpToVerify.values()[0]: + test.passes("Breakpoint at expected line (%d) inside expected file (%s)" + % (line, fileName)) + return True + else: + test.fail("Breakpoint did not match expected line/file", + "Found: %d in %s" % (line, fileName)) + else: + test.fatal("Expected a dict for bpToVerify - got '%s'" % className(bpToVerify)) + return False diff --git a/tests/system/suite_debugger/tst_simple_debug/test.py b/tests/system/suite_debugger/tst_simple_debug/test.py new file mode 100644 index 0000000000000000000000000000000000000000..4dce12bab11afca2be1dd105017dd742a7be7153 --- /dev/null +++ b/tests/system/suite_debugger/tst_simple_debug/test.py @@ -0,0 +1,62 @@ +source("../../shared/qtcreator.py") + +workingDir = None + +def main(): + global workingDir + startApplication("qtcreator" + SettingsPath) + if not checkDebuggingLibrary("4.8.0", [QtQuickConstants.Targets.DESKTOP]): + test.fatal("Error while checking debugging libraries - leaving this test.") + invokeMenuItem("File", "Exit") + return + # using a temporary directory won't mess up a potentially existing + workingDir = tempDir() + projectName = createNewQtQuickApplication(workingDir, targets = QtQuickConstants.Targets.DESKTOP) + # wait for parsing to complete + waitForSignal("{type='CppTools::Internal::CppModelManager' unnamed='1'}", + "sourceFilesRefreshed(QStringList)") + editor = waitForObject("{type='QmlJSEditor::QmlJSTextEditorWidget' unnamed='1' " + "visible='1' window=':Qt Creator_Core::Internal::MainWindow'}") + if placeCursorToLine(editor, "MouseArea.*", True): + type(editor, '<Up>') + type(editor, '<Return>') + type(editor, 'Component.onCompleted: console.log("Break here")') + invokeMenuItem("File", "Save All") + filesAndLines = { + "%s.QML.qml/%s.main\\.qml" % (projectName,projectName) : 'Component.onCompleted.*', + "%s.Sources.main\\.cpp" % projectName : "viewer.setOrientation\\(.+\\);" + } + test.log("Setting breakpoints") + result = setBreakpointsForCurrentProject(filesAndLines) + if result: + expectedBreakpointsOrder = [{"main.cpp":9}, {"main.qml":11}] + availableConfigs = iterateBuildConfigs(1, 0, ".*4\.8(\.\d+)?.*$(?<![Rr]elease)") + if not availableConfigs: + test.fatal("Haven't found a suitable Qt version (need Qt >= 4.8) - leaving without debugging.") + for config in availableConfigs: + test.log("Selecting '%s' as build config" % config) + selectBuildConfig(1, 0, config) + verifyBuildConfig(1, 0, True) + # explicitly build before start debugging for adding the executable as allowed program to WinFW + invokeMenuItem("Build", "Rebuild All") + waitForSignal("{type='ProjectExplorer::BuildManager' unnamed='1'}", + "buildQueueFinished(bool)", 300000) + if not checkCompile(): + test.fatal("Compile had errors... Skipping current build config") + continue + allowAppThroughWinFW(workingDir, projectName, False) + if not doSimpleDebugging(config, 2, expectedBreakpointsOrder): + try: + stopB = findObject(':Qt Creator.Stop_QToolButton') + if stopB.enabled: + clickButton(stopB) + except: + pass + deleteAppFromWinFW(workingDir, projectName, False) + # close application output window of current run to avoid mixing older output on the next run + ensureChecked(":Qt Creator_AppOutput_Core::Internal::OutputPaneToggleButton") + clickButton(waitForObject("{type='CloseButton' unnamed='1' visible='1' " + "window=':Qt Creator_Core::Internal::MainWindow'}")) + else: + test.fatal("Setting breakpoints failed - leaving without testing.") + invokeMenuItem("File", "Exit")