tests/auto/qml/qmldesigner/propertyeditortests/tst_propertyeditor
tests/auto/profilewriter/tst_profilewriter
src/tools/cplusplus/generate-ast
+src/tools/qml/qmldump/qmldump
-Qt Creator 2.0.80
+Qt Creator 2.1.80
===============
Qt Creator is a crossplatform C++ IDE for development with the Qt framework.
qmake $SOURCE_DIRECTORY/qtcreator.pro
make (or mingw32-make or nmake or jom, depending on your platform)
-Qml Support
------------
-
-Define the QTCREATOR_WITH_QML environment variable to enable Qml support
-(before running qmake).
-
QmlDesigner, QmlInspector require private headers
-------------------------------------------------
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
//! [class implementation]
#include "addressbook.h"
#include "ui_addressbook.h"
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
//! [class definition]
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
//! [main function]
#include <QApplication>
#include "addressbook.h"
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#include "addressbook.h"
#include "ui_addressbook.h"
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
//! [main function]
#include <QApplication>
#include "addressbook.h"
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#include "addressbook.h"
#include "ui_addressbook.h"
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#include <QApplication>
#include "addressbook.h"
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#include "addressbook.h"
#include "ui_addressbook.h"
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#include <QApplication>
#include "addressbook.h"
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#include "addressbook.h"
#include "ui_addressbook.h"
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#include "finddialog.h"
#include "ui_finddialog.h"
#include <QMessageBox>
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#ifndef FINDDIALOG_H
#define FINDDIALOG_H
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#include <QApplication>
#include "addressbook.h"
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#include <QFileDialog>
#include "addressbook.h"
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#include "finddialog.h"
#include "ui_finddialog.h"
#include <QMessageBox>
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#ifndef FINDDIALOG_H
#define FINDDIALOG_H
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#include <QApplication>
#include "addressbook.h"
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#include <QFileDialog>
#include <QTextStream>
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#include "finddialog.h"
#include "ui_finddialog.h"
#include <QMessageBox>
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#ifndef FINDDIALOG_H
#define FINDDIALOG_H
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+**************************************************************************/
+
#include <QApplication>
#include "addressbook.h"
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
-** Commercial Usage
-**
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
-**
-** GNU Lesser General Public License Usage
-**
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
**************************************************************************/
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
-** Commercial Usage
+** You may use this file under the terms of the BSD license as follows:
**
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
**
-** GNU Lesser General Public License Usage
-**
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
**************************************************************************/
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
-** Commercial Usage
+** You may use this file under the terms of the BSD license as follows:
**
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
**
-** GNU Lesser General Public License Usage
-**
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
**************************************************************************/
-HTML.stylesheets = style/style.css \
- style/OfflineStyle.css \
- style/style_ie7.css \
- style/style_ie8.css \
- style/style_ie6.css
-
+HTML.stylesheets = style/style.css
HTML.postheader = " <div class=\"header\" id=\"qtdocheader\">\n" \
- " <div class=\"content\"> \n" \
" <div id=\"nav-logo\">\n" \
" <a href=\"index.html\">Home</a></div>\n" \
" <a href=\"index.html\" class=\"qtref\"><span>Qt Creator Documentation</span></a>\n" \
- " <div id=\"narrowsearch\"><form onsubmit=\"return false;\" action=\"\" id=\"qtdocsearch\">\n" \
- " <fieldset>\n" \
- " <input type=\"text\" value=\"\" id=\"pageType\" name=\"searchstring\">\n" \
- " </fieldset>\n" \
- " </form></div>\n" \
" <div id=\"nav-topright\">\n" \
" <ul>\n" \
" <li class=\"nav-topright-home\"><a href=\"http://qt.nokia.com/\">Qt HOME</a></li>\n" \
" </div>\n" \
" <div id=\"shortCut\">\n" \
" <ul>\n" \
- " <li class=\"shortCut-topleft-inactive\"><span><a href=\"index.html\">Qt Creator 2.0.80 </a></span></li>\n" \
- " <li class=\"shortCut-topleft-active\"><a href=\"http://qt.nokia.com/doc/\">ALL VERSIONS" \
+ " <li class=\"shortCut-topleft-inactive\"><span><a href=\"index.html\">Qt Creator 2.1.80 </a></span></li>\n" \
+ " <li class=\"shortCut-topleft-active\"><a href=\"http://qt.nokia.com/doc/\">ALL Versions" \
" </a></li>\n" \
" </ul>\n" \
- " </div>\n" \
" </div>\n" \
" </div>\n" \
" <div class=\"wrapper\">\n" \
" <div class=\"searchlabel\">\n" \
" Search index:</div>\n" \
" <div class=\"search\">\n" \
- " <form id=\"qtdocsearch\" action=\"\" onsubmit=\"return false;\">\n" \
+ " <form id=\"qtdocsearch\" action=\"#\">\n" \
" <fieldset>\n" \
- " <input type=\"text\" name=\"searchstring\" id=\"pageType\" value=\"\" />\n" \
+ " <input type=\"text\" name=\"searchstring\" id=\"searchstring\" value=\"\" onkeyup=\"doSearch(this.value);\" />\n" \
" </fieldset>\n" \
" </form>\n" \
" </div>\n" \
" <div class=\"box first bottombar\" id=\"lookup\">\n" \
- " <h2 title=\"API Lookup\"><span></span>\n" \
+ " <h2>\n" \
" API Lookup</h2>\n" \
- " <div id=\"list001\" class=\"list\">\n" \
- " <ul id=\"ul001\" >\n" \
- " <li class=\"defaultLink\"><a href=\"classes.html\">Class index</a></li>\n" \
- " <li class=\"defaultLink\"><a href=\"functions.html\">Function index</a></li>\n" \
- " <li class=\"defaultLink\"><a href=\"modules.html\">Modules</a></li>\n" \
- " <li class=\"defaultLink\"><a href=\"namespaces.html\">Namespaces</a></li>\n" \
- " <li class=\"defaultLink\"><a href=\"qtglobal.html\">Global stuff</a></li>\n" \
- " <li class=\"defaultLink\"><a href=\"qdeclarativeelements.html\">QML elements</a></li>\n" \
- " </ul> \n" \
+ " <div class=\"list\">\n" \
+ " <ul>\n" \
+ " <li><a href=\"modules.html\">All modules</a></li>\n" \
+ " <li><a href=\"classes.html\">All classes</a></li>\n" \
+ " <li><a href=\"functions.html\">All functions</a></li>\n" \
+ " <li><a href=\"namespaces.html\">All namespaces</a></li>\n" \
+ " <li><a href=\"platform-specific.html\">Platform specifics</a></li>\n" \
+ " </ul>\n" \
+ " </div>\n" \
+ " <div class=\"live\">\n" \
" </div>\n" \
" </div>\n" \
" <div class=\"box bottombar\" id=\"topics\">\n" \
- " <h2 title=\"Qt Topics\"><span></span>\n" \
- " Qt Topics</h2>\n" \
- " <div id=\"list002\" class=\"list\">\n" \
- " <ul id=\"ul002\" >\n" \
- " <li class=\"defaultLink\"><a href=\"qt-basic-concepts.html\">Basic Qt architecture</a></li>\n" \
- " <li class=\"defaultLink\"><a href=\"declarativeui.html\">Device UI's & Qt Quick</a></li>\n" \
- " <li class=\"defaultLink\"><a href=\"qt-gui-concepts.html\">Desktop UI components</a></li>\n" \
- " <li class=\"defaultLink\"><a href=\"platform-specific.html\">Platform-specific info</a></li>\n" \
- " </ul> \n" \
+ " <h2>\n" \
+ " API Topics</h2>\n" \
+ " <div class=\"list\">\n" \
+ " <ul>\n" \
+ " <li><a href=\"object.html\">QObject model</a></li>\n" \
+ " <li><a href=\"eventsandfilters.html\">Events, signals & slots</a></li>\n" \
+ " <li><a href=\"paintsystem.html\">Graphics & Paint system</a></li>\n" \
+ " <li><a href=\"declarativeui.html\">Qt Quick</a></li>\n" \
+ " <li><a href=\"widgets-and-layouts.html\">Widget style & layout</a></li>\n" \
+ " </ul>\n" \
+ " </div>\n" \
+ " <div class=\"live\">\n" \
" </div>\n" \
" </div>\n" \
" <div class=\"box\" id=\"examples\">\n" \
- " <h2 title=\"Examples\"><span></span>\n" \
- " Examples</h2>\n" \
- " <div id=\"list003\" class=\"list\">\n" \
- " <ul id=\"ul003\">\n" \
- " <li class=\"defaultLink\"><a href=\"all-examples.html\">Examples</a></li>\n" \
- " <li class=\"defaultLink\"><a href=\"tutorials.html\">Tutorials</a></li>\n" \
- " <li class=\"defaultLink\"><a href=\"demos.html\">Demos</a></li>\n" \
- " <li class=\"defaultLink\"><a href=\"qdeclarativeexamples.html\">QML Examples</a></li>\n" \
- " <li class=\"defaultLink\"><a href=\"qdeclarativeexamples.html#Demos\">QML Demos</a></li>\n" \
- " </ul> \n" \
+ " <h2>\n" \
+ " API Examples</h2>\n" \
+ " <div class=\"list\">\n" \
+ " <ul>\n" \
+ " <li><a href=\"examples.html\">All examples</a></li>\n" \
+ " <li><a href=\"tutorials.html\">All tutorials</a></li>\n" \
+ " <li><a href=\"examples.html\">Qt Quick examples</a></li>\n" \
+ " <li><a href=\"examples.html\">Desktop examples</a></li>\n" \
+ " <li><a href=\"examples.html\">Device examples</a></li>\n" \
+ " </ul>\n" \
+ " </div>\n" \
+ " <div class=\"live\">\n" \
" </div>\n" \
" </div>\n" \
" </div>\n" \
" <li id=\"medA\" class=\"t_button active\">A</li>\n" \
" <li id=\"bigA\" class=\"t_button\">A</li>\n" \
" <li id=\"print\" class=\"t_button\"><a href=\"javascript:this.print();\">\n" \
- " <span>Print</span></a></li>\n" \
+ " <img src=\"images/sep.png\" alt=\"\" /><img id=\"printIcon\" src=\"images/print.png\" alt=\"Print this page\" /></a></li>\n" \
" </ul>\n" \
" </div>\n" \
" </div>\n" \
" <div class=\"content\">\n"
-HTML.footer = " <!-- /div -->\n" \
- " <div class=\"feedback t_button\">\n" \
+HTML.footer = " </div>\n" \
+ " <div class=\"feedback t_button\" onclick=\"\$(\'#feedbackBox\').show();\$(\'#blurpage\').show()\">\n" \
" [+] Documentation Feedback</div>\n" \
" </div>\n" \
" </div>\n" \
" <div class=\"ft\">\n" \
" <span></span>\n" \
" </div>\n" \
- " </div> \n" \
" <div class=\"footer\">\n" \
" <p>\n" \
" <acronym title=\"Copyright\">©</acronym> 2008-2010 Nokia Corporation and/or its\n" \
" href=\"http://qt.nokia.com/about/privacy-policy\">Privacy Policy</a></p>\n" \
" </div>\n" \
" <div id=\"feedbackBox\">\n" \
- " <div id=\"feedcloseX\" class=\"feedclose t_button\">X</div>\n" \
- " <form id=\"feedform\" action=\"http://doc.qt.nokia.com/docFeedbck/feedback.php\" method=\"get\">\n" \
- " <p><textarea id=\"feedbox\" name=\"feedText\" rows=\"5\" cols=\"40\">Please submit you feedback...</textarea></p>\n" \
- " <p><input id=\"feedsubmit\" class=\"feedclose\" type=\"submit\" name=\"feedback\" /></p>\n" \
+ " <div id=\"feedcloseX\">\n" \
+ " <a href=\"#\" onclick=\"\$(\'#feedbackBox\').hide();\$(\'#blurpage\').hide()\">X</a>\n" \
+ " </div>\n" \
+ " <form action=\"#\">\n" \
+ " <textarea id=\"feedbox\" rows=\"5\" cols=\"40\">Please submit you feedback...</textarea>\n" \
+ " <input id=\"feedsubmit\" type=\"submit\" onclick=\"\$(\'#feedbackBox\').hide();\$(\'#blurpage\').hide()\"\n" \
+ " name=\"feedback\" />\n" \
" </form>\n" \
" </div>\n" \
" <div id=\"blurpage\">\n" \
\title Qt Creator Manual
- \section1 Version 2.0
+ \section1 Version 2.1.80
Qt Creator provides integrated tools for both application designers
and developers to create applications for multiple desktop and mobile device
platforms.
- For application designers, Qt Creator provides an integrated
- visual editor, \QD,
- \if defined(qtquick)
- and \QMLD
- \endif
- that you can use to design and develop
+ For application designers, Qt Creator provides two integrated
+ visual editors, \QD and \QMLD, that you can use to design and develop
application user interfaces.
For application developers,
\o \l{Building and Running an Example Application}
\o \l{Creating a Qt C++ Application}
\o \l{Creating a Mobile Application with Nokia Qt SDK}
- \if defined(qtquick)
\o \l{Creating a Qt Quick Application}
- \endif
\endlist
\o \l{Using the Editor}
\list
\o \l{Specifying Editor Settings}
\o \l{Specifying Dependencies}
\endlist
- \if defined(qtquick)
\o \l{Developing Qt Quick Applications}
- \endif
\o \l{Optimizing Applications for Mobile Devices}
\o \l{Using the Maemo Emulator}
\o \l{Debugging}
\o \l{Setting Up Debugger}
\o \l{Using Debugging Helpers}
\endlist
- \if defined(qtquick)
\o \l{Debugging Qt Quick Applications}
- \endif
- \if defined(qtquick)
\list
\o \l{Using the QML Inspector}
\endlist
- \endif
\endlist
\o \l{Using Version Control Systems}
\o \l{Adding Qt Designer Plugins}
\section1 Designing User Interfaces
- \if defined(qtquick)
-
Qt Creator provides two integrated visual editors, \QD and \QMLD.
- \endif
-
\QD is a tool for designing and building graphical user interfaces (GUIs) from
Qt widgets. You can compose and customize your widgets or dialogs and test
them using different styles and resolutions.
Furthermore, features like widget promotion and custom plugins allow you to use your
own widgets with \QD.
- \if defined(qtquick)
-
UIs that use widgets are clearly structured and enforce a platform look and feel,
which makes them useful for traditional applications. However, they are static, and
do not fully make use of the large high-resolution screens, touch input, and significant
and interaction to specify user actions that change the states. You
can use Qt or JavaScript to implement the application logic.
- \endif
-
\section1 Coding Applications
As an IDE, Qt Creator differs from a text editor in that it knows how to build and run
interface (GUI) application, Qt Creator generates an empty .ui file
that you can modify with the integrated \QD.
- \if defined(qtquick)
-
If you choose to create a Qt Quick application, Qt Creator generates a .qml file
that you can modify with the \QMLD visual editor and the code editor.
-
- \endif
*/
/*!
\list
\o \gui Welcome mode for opening recent sessions and projects.
\o \gui{\l{Using the Editor}{Edit}} mode for editing project and source files.
- \if defined(qtquick)
\o \gui{\l{Developing Application UI}{Design}} mode for designing and developing
application user interfaces.
- \else
- \o \gui{\l{Using Qt Designer}{Design}} mode for designing and developing
- application user interfaces.
- \endif
\o \gui{\l{Debugging}{Debug}} mode for inspecting the state of your program while
debugging.
\o \gui{\l{Managing Projects}{Projects}} mode for configuring project building and
\l{Searching With the Locator}{navigation} shortcuts are available to help
speed up the process of developing your application.
- \if defined(qtquick)
-
\section1 Developing Application UI
To help you design the user interface of your application, two visual
The integration includes project management and code completion.
- \endif
-
\section1 Using Qt Designer
Qt Creator automatically opens all .ui files in \QD.
For more information on \QD, see
\l{http://doc.qt.nokia.com/4.7-snapshot/designer-manual.html}{Qt Designer Manual}.
- \if defined(qtquick)
-
\section1 Using Qt Quick Designer
You can edit .qml files in the visual \QMLD editor or in the
\endlist
- \endif
-
*/
Qt Creator understands the code as code, not just as plain text. This
allows it to help you to write well formatted code and to anticipate
- what you are going to write and complete the code.
- \if defined(qtquick)
- The code completion differs somewhat depending on whether you write Qt code or QML code.
- \endif
-
- \if defined(qtquick)
+ what you are going to write and complete the code. The code completion
+ differs somewhat depending on whether you write Qt code or QML code.
\section2 Completing Qt Code
- \endif
-
As you write code, Qt Creator provides a list of context-sensitive
suggestions to the statement currently under your cursor.
\i A namespace
\endtable
- \if defined(qtquick)
-
\section2 Completing QML Code
As you write QML code, Qt Creator suggests properties, IDs, and code
\image qmldesigner-code-completion.png "Completing QML code"
- \endif
-
\section1 Using Bookmarks
To insert or delete a bookmark right-click the line number and select
\section1 Using Update Code Model
To refresh the internal information in Qt Creator pertaining to your code,
- select \gui{Tools} > \gui{C++} > \gui{Update Code Model}.
+ select \gui{Tools} > \gui{C++} > \gui{Update code model}.
\note In Qt Creator indexing updates the code automatically. Use
- \gui{Update Code Model} only as an emergency command.
+ \gui{Update code model} only as an emergency command.
*/
In the \gui{FakeVim} mode, you can run the main editor in a manner similar
to the Vim editor. To run the editor in the \gui{FakeVim} mode, select
- \gui{Edit} > \gui{Advanced} > \gui{Use Vim-style Editing} or press
+ \gui{Edit} > \gui{Advanced} > \gui{Use vim-style editing} or press
\key{Alt+V,Alt+V}.
In the \gui{FakeVim} mode, most keystrokes in the main editor will be
\section1 Renaming Symbols
- \if defined(qtquick)
-
The functions used to rename symbols depends on whether you are
writing C++ or QML code. For QML, you can only rename IDs.
- \endif
-
To rename a specific symbol in a Qt project:
\list 1
\o In the editor, place the cursor on the symbol you would like to
The instances of the symbol are highlighted in code and you can edit the
symbol. All instances of the local symbol are changed as you type.
- \if defined(qtquick)
-
To rename an ID in a Qt Quick project:
\list 1
\o In the \gui {Rename id} field, enter the new ID.
\endlist
-
- \endif
*/
/*!
\title Creating a Project
You use wizards to create and import several types of projects and files, such
- as Qt GUI or console applications.
- \if defined(qtquick)
- and Qt Quick applications
- \endif
- You can also use
+ as Qt GUI or console applications and Qt Quick applications. You can also use
wizards to add individual files to your projects. For example, you can create
the following types of files:
\o Qt resource files, which allow you to store binary files in the
application executable
- \if defined(qtquick)
-
\o \QD forms and Qt QML files, which specify parts of application user
interfaces
- \endif
-
\o C++ class, source, or header files
\endlist
\gui{Qt Versions}.
\o Qt Creator automatically sets the correct environment variables for
compilation. Select the internal version number of the installed
- Microsoft Visual C++ tool chain in the \gui Toolchain list.
+ Microsoft Visual C++ tool chains using the \gui MSVC drop-down
+ box:
+ \list
+ \o \bold 7.1 for Visual Studio 2003
+ \o \bold 8.0 for Visual Studio 2005
+ \o \bold 9.0 for Visual Studio 2008
+ \endlist
+
+ \note If you are using the
+ \bold{Windows SDK for Windows Server 2008}, Qt Creator identifies
+ it as version 9.0.
\image qtcreator-qt4-qtversions-win-msvc.png
\endlist
set up automatically.
You can select the targets and click the \gui Run button to build and
- run the applications on the targets. You can click the \gui {Build All}
- button to build all open projects, one after another.
+ run the applications on the targets.
\section1 Setting Up a Project
{Complete Guide to Symbian Signed}.
When you have your own certificate and private key, you can specify them in
- the \gui{Create SIS Package} step in your build configuration.
+ the \gui{Create sis Package} step in your build configuration.
\image qtcreator-qt4-symbian-signing.png
\gui{Add clean step} and select the type of step you want to add.
By default, custom steps are disabled. Activate custom steps by
- checking the \gui{Enable custom process step} check-box.
- \o To remove a clean step, click \gui{Remove Item}.
+ checking the \gui{Enable Custom Process Step} check-box.
+ \o To remove a clean step, click \gui{Remove clean step} and select the
+ step you want to remove.
\o To change the order of steps, click
\inlineimage qtcreator-movestep.png
.
Qt Creator automatically creates run configurations for your project.
To view and modify the settings, select \gui {Projects > Run}.
-
- \if defined(qtquick)
The settings to specify depend on the type of the project: qmake project
or Qt Quick project.
- \endif
Click \gui Add to add run settings for a project and \gui Remove to remove
the current settings.
\image qmldesigner-run-custom-exe.png "Run settings for custom executables"
- \if defined(qtquick)
-
\section1 Specifying Run Settings for Qt Quick Projects
Select run settings in the \gui {Run configuration} field. The settings
\image qmldesigner-run-settings.png "Run settings for Qt Quick projects"
- \endif
-
*/
\title Getting Started
- This section contains examples that illustrate how to use Qt Creator
- \if defined(qtquick)
- and the integrated design tools, \QD and \QMLD,
- \endif
- to create, build, and run simple
+ This section contains examples that illustrate how to use Qt Creator and the
+ integrated design tools, \QD and \QMLD, to create, build, and run simple
applications:
\list
\o \l{Building and Running an Example Application}
\o \l{Creating a Qt C++ Application}
\o \l{Creating a Mobile Application with Nokia Qt SDK}
- \if defined(qtquick)
\o \l{Creating a Qt Quick Application}
- \endif
\endlist
*/
/*!
- \if defined(qtquick)
\contentspage index.html
\previouspage creator-mobile-example.html
\page creator-qml-application.html
\note In the \gui {QML Viewer}, select \gui {Skin} and select a mobile device
type to view the application as on a mobile device.
- \endif
*/
a rebase operation while pulling.
\row
- \i \gui{Clean Repository.../Clean Project...}
+ \i \gui{Clean repository.../Clean project...}
\i Collect all files that are not under version control
with the exception of patches and project files
and show them as a checkable list in a dialog
\row
\i \gui{Stashes...}
\i Displays a dialog showing the stashes created by
- \gui{Stash Snapshot...} with options to restore,
+ \gui{Stash snapshots...} with options to restore,
display or delete them.
\row
\i \gui {Stage File for Commit}
To create a locator filter:
\list 1
\o In the locator, click \inlineimage qtcreator-locator-magnify.png
- and select \gui Configure.... to open the \gui Locator options.
+ and select \gui Configure....
\image qtcreator-locator-customize.png
- \o Click \gui Add.
- \o In the \gui{Filter Configuration} dialog:
+ \o In the \gui{Options...} window click \gui Add.
+ \o In the \gui{Filters} dialog:
\list
\o Name your filter.
\o Select at least one directory. The locator searches directories
The locator searches the files matching your file pattern in the
directories you have selected and caches that information. The cache for
- all default filters is updated as you write your code. By default,
- Qt Creator updates the filters created by you once an hour.
+ all default filters is updated as you write your code. The filters you have
+ created Qt Creator by default updates once an hour.
To update the cached information manually, click
\inlineimage qtcreator-locator-magnify.png
To set a new cache update time:
\list 1
\o Select \gui Tools > \gui Options... > \gui Locator.
- \o In \gui{Refresh interval}, define new time in minutes.
+ \o In \gui{Refresh interval} define new time in minutes.
\endlist
*/
\title Managing Sessions
- When you exit Qt Creator, a snapshot of your current workspace is stored
- as a session.
- A session is a collection of:
+ In Qt Creator, a session is a collection of:
\list
\o Open projects with their dependencies
\o Bookmarks
\endlist
- If you work on a project and need to switch to another project for a
- while, you can save your workspace as a session. This makes it easier
- to return to working on the first project later.
-
- To create a new session or remove existing sessions, select \gui File >
- \gui Sessions > \gui{Session Manager}.
-
- \image qtcreator-session-manager.png
-
- To switch between sessions, choose
- \gui File > \gui Session. If you do not create or select a session,
- Qt Creator always uses the default session, which was created the
- last time you exited Qt Creator.
-
When you launch Qt Creator, a list of existing sessions is displayed on the
\gui{Welcome screen}.
\image qtcreator-welcome-session.png
+ To switch between sessions, select the session from sessions listed in
+ \gui File > \gui Session. If you do not create or select a session,
+ Qt Creator always uses the default session.
+
+ To create a new session or remove existing sessions, select \gui File >
+ \gui Sessions > \gui{Session Manager}.
+
+ \image qtcreator-session-manager.png
*/
\title Debugging
You can use the Qt Creator \gui Debug mode to inspect the state of your
- Qt
- \if defined(qtquick)
- and Qt Quick
- \endif
- projects while debugging.
+ Qt and Qt Quick projects while debugging.
Qt Creator does not include a debugger. It provides a debugger plugin that acts
as an interface between the Qt Creator core and external native debuggers
\image qtcreator-debugger-views.png "Native debugger views"
- \if defined(qtquick)
-
Qt Creator includes a QML inspector plugin that you can use to debug QML.
\image qmldesigner-inspector.png "QML inspector views"
\gui QML. You can also press \key {Ctrl+L, 1} to switch to the native debugger and
\key {Ctrl+L, 2} to switch to the QML inspector.
- \endif
-
*/
/*!
- \if defined(qtquick)
\contentspage index.html
\previouspage creator-debugging-helpers.html
\page creator-debugging-qml.html
You must use the native debugger to set breakpoints to C++ code and to examine
the state of the interrupted Qt application. When a C++ program is interrupted,
for example when a breakpoint is hit, you cannot use the QML inspector.
- \endif
*/
/*!
- \if defined(qtquick)
\contentspage index.html
\previouspage creator-debugging-qml.html
\page creator-qml-inspector.html
by another application or another instance of \QQV that was not shut
down properly. You can specify any free port number in the registered port range
(1024-49151).
- \endif
*/
\section2 Terminal Mode
To launch the debugger in the terminal mode, select \gui {Projects > Run Settings}
- and select the \gui {Run in terminal} check box. Then click the
+ and select the \gui {Run in Terminal} check box. Then click the
\gui {Start Debugging} button for the active project.
\section2 Attach Mode
To enable Qt's basic objects data display feature:
\list
\o Select \gui Tools > \gui {Options...} > \gui Debugger >
- \gui{Debugging Helper} and check the \gui{Use Debugging Helper}
+ \gui{Debugging Helper} and check the \gui{Use debugging helper}
checkbox.
\o The \gui{Locals and Watchers} view is reorganized to provide a
high-level view of the objects.
\section2 Children and SubItem Class
- The attempt to create child items might lead to errors if data is
- uninitialized or corrupted. To gracefully recover in such situations,
- use \c Children and \c SubItem \e{Context Managers} to create the nested items.
+ Child items might report errors if data is uninitialized or corrupted
+ or if the helper code is broken. To gracefully recover from these
+ errors, use \c Children and \c SubItem \e{Context Managers} to create
+ nested items.
The \c Children constructor \gui{__init__(self, dumper, numChild = 1,
- childType = None, childNumChild = None)} uses one mandatory argument and three
- optional arguments. The mandatory argument refers to the current \c Dumper
- object. The optional arguments can be used to specify the number \c numChild
- of children, with type \c childType_ and \c childNumChild_ grandchildren each.
- If \c numChild_ is a list of two integers, the first one specifies the actual
- number of children and the second the maximum number of children to print.
+ childType = None, childNumChild = None)} uses one non-optional argument
+ \c dumper to refer to the current \c Dumper object and three optional
+ arguments, specifying the number \c numChild of children, with type
+ \c childType_ and \c childNumChild_ grandchildren each. If \c numChild_
+ is a list of two integers, the first one specifies the actual number
+ of children and the second the maximum number of children to print.
Similarly, using the \SubItem class helps to protect individual items.
\section1 Setting the Path for CMake
You can set the path for the \c CMake executable in \gui{Tools} >
- \gui{Options... > Projects > CMake}.
+ \gui{Options...} > \gui{CMake} > \gui{CMake}.
\image qtcreator-cmakeexecutable.png
information about the Maemo platform, see
\l{http://maemo.org/intro/platform/}{Software Platform} on the Maemo web site.
- For more information about developing applications for the Maemo 5
- platform, select \gui {Help > Index} and look for \gui {Platform Notes},
- or see
- \l{http://doc.qt.nokia.com/qt-maemo-4.6/platform-notes.html}{Platform Notes - Maemo 5}.
\section1 Hardware and Software Requirements
\o In the \gui {Configuration name} field, enter a name for
the connection.
- \o In the \gui {Device type} field, select \gui {Maemo emulator}.
+ \o In the \gui {Device type} field, select \gui {Local simulator}.
\o In the \gui {Authentication type} field, select \gui Password
for the initial connection.
\title Setting Up Development Environment for Symbian
- For more information about developing applications for the Symbian
- platform, select \gui {Help > Index} and look for \gui {Platform Notes},
- or see
- \l{http://doc.qt.nokia.com/4.6/platform-notes-symbian.html}{Platform Notes - Symbian}.
-
\section1 Hardware and Software Requirements
Windows is the only development platform for the Symbian target
\o Choose \gui {Start > Nokia Qt SDK > Symbian > Install TRK to Symbian
device} and follow the instructions on the screen to install the TRK
- debugging application on the device.
+ debugging application for S60 5th Edition devices on the device.
- \note To check the Symbian platform version of your device, see
- \l{http://www.forum.nokia.com/devices}{Device Details}.
+ \o Start TRK on the device.
\endlist
\list 1
\o Select \gui Tools > \gui Options... > \gui Debugger >
\gui{Debugging Helper}.
- \o Uncheck the \gui{Use Debugging Helper} checkbox.
+ \o Uncheck the \gui{Use debugging helper} checkbox.
\endlist
*/
qhp.projects = QtCreator
qhp.QtCreator.file = qtcreator.qhp
-qhp.QtCreator.namespace = com.nokia.qtcreator.2080
+qhp.QtCreator.namespace = com.nokia.qtcreator.2180
qhp.QtCreator.virtualFolder = doc
qhp.QtCreator.indexTitle = Qt Creator
-qhp.QtCreator.filterAttributes = qtcreator 2.0.80
-qhp.QtCreator.customFilters.QtCreator.name = Qt Creator 2.0.80
-qhp.QtCreator.customFilters.QtCreator.filterAttributes = qtcreator 2.0.80
+qhp.QtCreator.filterAttributes = qtcreator 2.1.80
+qhp.QtCreator.customFilters.QtCreator.name = Qt Creator 2.1.80
+qhp.QtCreator.customFilters.QtCreator.filterAttributes = qtcreator 2.1.80
qhp.QtCreator.indexRoot =
qhp.QtCreator.extraFiles = \
style/style.css \
style/style_ie6.css \
style/style_ie7.css \
style/style_ie8.css \
- style/OfflineStyle.css \
images/qt-logo.png \
images/qtcreator-screenshots.png \
scripts/functions.js \
IDE_LIBEXEC_PATH = $$IDE_APP_PATH/$${IDE_APP_TARGET}.app/Contents/Resources
IDE_DATA_PATH = $$IDE_APP_PATH/$${IDE_APP_TARGET}.app/Contents/Resources
IDE_DOC_PATH = $$IDE_DATA_PATH/doc
+ IDE_BIN_PATH = $$IDE_APP_PATH/$${IDE_APP_TARGET}.app/Contents/MacOS
contains(QT_CONFIG, ppc):CONFIG += ppc x86
copydata = 1
} else {
IDE_LIBEXEC_PATH = $$IDE_APP_PATH # FIXME
IDE_DATA_PATH = $$IDE_BUILD_TREE/share/qtcreator
IDE_DOC_PATH = $$IDE_BUILD_TREE/share/doc/qtcreator
+ IDE_BIN_PATH = $$IDE_APP_PATH
!isEqual(IDE_SOURCE_TREE, $$IDE_BUILD_TREE):copydata = 1
}
from __future__ import with_statement
-#Note: Keep name-type-value-numchild-extra order
-
-#return
import sys
import gdb
import __builtin__
import os
+
# Fails on Windows.
try:
import curses.ascii
# and gdb.VERSION != "6.8.50.20090630-cvs"
return 'parse_and_eval' in __builtin__.dir(gdb)
+typeCache = {}
+
+def lookupType(typestring):
+ type = typeCache.get(typestring)
+ #warn("LOOKUP: %s -> %s" % (typestring, type))
+ if type is None:
+ type = gdb.lookup_type(typestring)
+ typeCache[typestring] = type
+ return type
+
def cleanAddress(addr):
if addr is None:
return "<no address>"
# We cannot use str(addr) as it yields rubbish for char pointers
# that might trigger Unicode encoding errors.
- return addr.cast(gdb.lookup_type("void").pointer())
+ return addr.cast(lookupType("void").pointer())
# Workaround for gdb < 7.1
def numericTemplateArgument(type, position):
hasBlock = 'block' in __builtin__.dir(frame)
items = []
+ #warn("HAS BLOCK: %s" % hasBlock);
+ #warn("IS GOOD GDB: %s" % isGoodGdb());
if hasBlock and isGoodGdb():
#warn("IS GOOD: %s " % varList)
try:
check(count < 1000000) # assume there aren't a million references to any object
#def couldBePointer(p, align):
-# type = gdb.lookup_type("unsigned int")
+# type = lookupType("unsigned int")
# ptr = gdb.Value(p).cast(type)
# d = int(str(ptr))
# warn("CHECKING : %s %d " % (p, ((d & 3) == 0 and (d > 1000 or d == 0))))
# for invalid char *, as their "contents" is being examined
#s = str(p)
#return s == "0x0" or s.startswith("0x0 ")
- return p.cast(gdb.lookup_type("void").pointer()) == 0
+ return p.cast(lookupType("void").pointer()) == 0
movableTypes = set([
"QBrush", "QBitArray", "QByteArray",
def extractCharArray(p, maxsize):
- t = gdb.lookup_type("unsigned char").pointer()
+ t = lookupType("unsigned char").pointer()
p = p.cast(t)
i = findFirstZero(p, maxsize)
limit = select(i < 0, maxsize, i)
return extractCharArray(data, 100)
def encodeCharArray(p, maxsize, size = -1):
- t = gdb.lookup_type("unsigned char").pointer()
+ t = lookupType("unsigned char").pointer()
p = p.cast(t)
if size == -1:
i = findFirstZero(p, maxsize)
return s
def encodeChar2Array(p, maxsize):
- t = gdb.lookup_type("unsigned short").pointer()
+ t = lookupType("unsigned short").pointer()
p = p.cast(t)
i = findFirstZero(p, maxsize)
limit = select(i < 0, maxsize, i)
return s
def encodeChar4Array(p, maxsize):
- t = gdb.lookup_type("unsigned int").pointer()
+ t = lookupType("unsigned int").pointer()
p = p.cast(t)
i = findFirstZero(p, maxsize)
limit = select(i < 0, maxsize, i)
super(FrameCommand, self).__init__("bb", gdb.COMMAND_OBSCURE)
def invoke(self, args, from_tty):
+ if args.startswith("options:profile,"):
+ import cProfile
+ cProfile.run('bb("%s")' % args, "/tmp/bbprof")
+ else:
+ bb(args)
+
+FrameCommand()
+
+def bb(args):
+ Dumper(args)
+
+
+#######################################################################
+#
+# Step Command
+#
+#######################################################################
+
+
+class SalCommand(gdb.Command):
+ """Do fancy stuff."""
+
+ def __init__(self):
+ super(SalCommand, self).__init__("sal", gdb.COMMAND_OBSCURE)
+
+ def invoke(self, arg, from_tty):
+ (cmd, addr) = arg.split(",")
+ lines = catchCliOutput("info line *" + addr)
+ fromAddr = "0x0"
+ toAddr = "0x0"
+ for line in lines:
+ pos0from = line.find(" starts at address") + 19
+ pos1from = line.find(" ", pos0from)
+ pos0to = line.find(" ends at", pos1from) + 9
+ pos1to = line.find(" ", pos0to)
+ if pos1to > 0:
+ fromAddr = line[pos0from : pos1from]
+ toAddr = line[pos0to : pos1to]
+ gdb.execute("maint packet sal%s,%s,%s" % (cmd,fromAddr, toAddr))
+
+SalCommand()
+
+
+#######################################################################
+#
+# The Dumper Class
+#
+#######################################################################
+
+
+class Dumper:
+ def __init__(self, args):
+ self.output = ""
+ self.currentChildType = ""
+ self.currentChildNumChild = -1
+ self.currentMaxNumChilds = -1
+ self.currentNumChilds = -1
+ self.currentValue = None
+ self.currentValuePriority = -100
+ self.currentValueEncoding = None
+ self.currentType = None
+ self.currentTypePriority = -100
+ self.dumpers = ""
+ self.typeformats = {}
+ self.formats = {}
+ self.expandedINames = ""
+
options = []
varList = []
- typeformats = {}
- formats = {}
watchers = ""
- expandedINames = ""
+ resultVarName = ""
+
for arg in args.split(' '):
pos = arg.find(":") + 1
if arg.startswith("options:"):
elif arg.startswith("vars:"):
if len(arg[pos:]) > 0:
varList = arg[pos:].split(",")
+ elif arg.startswith("resultvarname:"):
+ resultVarName = arg[pos:]
elif arg.startswith("expanded:"):
- expandedINames = set(arg[pos:].split(","))
+ self.expandedINames = set(arg[pos:].split(","))
elif arg.startswith("typeformats:"):
for f in arg[pos:].split(","):
pos = f.find("=")
if pos != -1:
type = base64.b16decode(f[0:pos], True)
- typeformats[type] = int(f[pos+1:])
+ self.typeformats[type] = int(f[pos+1:])
elif arg.startswith("formats:"):
for f in arg[pos:].split(","):
pos = f.find("=")
if pos != -1:
- formats[f[0:pos]] = int(f[pos+1:])
+ self.formats[f[0:pos]] = int(f[pos+1:])
elif arg.startswith("watchers:"):
watchers = base64.b16decode(arg[pos:], True)
- useFancy = "fancy" in options
+ self.useFancy = "fancy" in options
+ self.passExceptions = "pe" in options
+ self.autoDerefPointers = "autoderef" in options
+ self.ns = qtNamespace()
+ #warn("NAMESPACE: '%s'" % self.ns)
#warn("VARIABLES: %s" % varList)
- #warn("EXPANDED INAMES: %s" % expandedINames)
+ #warn("EXPANDED INAMES: %s" % self.expandedINames)
module = sys.modules[__name__]
self.dumpers = {}
if False:
- dumpers = ""
- typeformats = ""
for key, value in module.__dict__.items():
if key.startswith("qdump__"):
- dumpers += '"' + key[7:] + '",'
- output = "dumpers=[%s]," % dumpers
+ self.dumpers += '"' + key[7:] + '",'
+ output = "dumpers=[%s]," % self.dumpers
#output += "qtversion=[%d,%d,%d]"
#output += "qtversion=[4,6,0],"
output += "namespace=\"%s\"," % qtNamespace()
return
- if useFancy:
+ if self.useFancy:
for key, value in module.__dict__.items():
if key.startswith("qdump__"):
self.dumpers[key[7:]] = value
- d = Dumper()
- d.dumpers = self.dumpers
- d.typeformats = typeformats
- d.formats = formats
- d.useFancy = useFancy
- d.passExceptions = "pe" in options
- d.autoDerefPointers = "autoderef" in options
- d.ns = qtNamespace()
- d.expandedINames = expandedINames
- #warn(" NAMESPACE IS: '%s'" % d.ns)
-
#
# Locals
#
- for item in listOfLocals(varList):
- with OutputSafer(d, "", ""):
- d.anonNumber = -1
+ locals = listOfLocals(varList);
+ if "nolocals" in options:
+ locals = []
+
+ # Take care of the return value of the last function call.
+ if len(resultVarName) > 0:
+ try:
+ value = parseAndEvaluate(resultVarName)
+ locals.append(Item(value, "return", resultVarName, "return"))
+ except:
+ # Don't bother. It's only supplementary information anyway.
+ pass
+
+ for item in locals:
+ with OutputSafer(self, "", ""):
+ self.anonNumber = -1
#warn("ITEM NAME %s: " % item.name)
try:
#warn("ITEM VALUE %s: " % item.value)
except:
# Locals with failing memory access.
with SubItem(d):
- d.put('iname="%s",' % item.iname)
- d.put('name="%s",' % item.name)
- d.put('addr="<not accessible>",')
- d.put('value="<not accessible>",')
- d.put('type="%s",' % item.value.type)
- d.put('numchild="0"');
+ self.put('iname="%s",' % item.iname)
+ self.put('name="%s",' % item.name)
+ self.put('addr="<not accessible>",')
+ self.put('value="<not accessible>",')
+ self.put('type="%s",' % item.value.type)
+ self.put('numchild="0"');
continue
type = item.value.type
n += 1
with SubItem(d):
- d.put('iname="%s",' % item.iname)
- d.putName(item.name)
- d.putItemCount(select(n <= 100, n, "> 100"))
- d.putType(type)
- d.putNumChild(n)
- if d.isExpanded(item):
+ self.put('iname="%s",' % item.iname)
+ self.putName(item.name)
+ self.putItemCount(select(n <= 100, n, "> 100"))
+ self.putType(type)
+ self.putNumChild(n)
+ if self.isExpanded(item):
p = item.value
- with Children(d, n):
+ with Children(self, n):
for i in xrange(n):
value = p.dereference()
- d.putItem(Item(value, item.iname, i, None))
+ self.putItem(Item(value, item.iname, i, None))
p += 1
if n > 100:
- d.putEllipsis()
+ self.putEllipsis()
else:
# A "normal" local variable or parameter.
try:
addr = cleanAddress(item.value.address)
- with SubItem(d):
- d.put('iname="%s",' % item.iname)
- d.put('addr="%s",' % addr)
- d.putItemHelper(item)
+ with SubItem(self):
+ self.put('iname="%s",' % item.iname)
+ self.put('addr="%s",' % addr)
+ self.putItemHelper(item)
except AttributeError:
# Thrown by cleanAddress with message "'NoneType' object
# has no attribute 'cast'" for optimized-out values.
with SubItem(d):
- d.put('iname="%s",' % item.iname)
- d.put('name="%s",' % item.name)
- d.put('addr="<optimized out>",')
- d.put('value="<optimized out>",')
- d.put('type="%s"' % item.value.type)
+ self.put('iname="%s",' % item.iname)
+ self.put('name="%s",' % item.name)
+ self.put('addr="<optimized out>",')
+ self.put('value="<optimized out>",')
+ self.put('type="%s"' % item.value.type)
#
# Watchers
#
- with OutputSafer(d, ",", ""):
+ with OutputSafer(self, ",", ""):
if len(watchers) > 0:
for watcher in watchers.split("##"):
(exp, iname) = watcher.split("#")
- self.handleWatch(d, exp, iname)
+ self.handleWatch(exp, iname)
#
# Breakpoints
#listOfBreakpoints(d)
#print('data=[' + locals + sep + watchers + '],bkpts=[' + breakpoints + ']\n')
- print('data=[' + d.output + ']')
+ print('data=[' + self.output + ']')
- def handleWatch(self, d, exp, iname):
+ def handleWatch(self, exp, iname):
exp = str(exp)
escapedExp = exp.replace('"', '\\"');
#warn("HANDLING WATCH %s, INAME: '%s'" % (exp, iname))
if exp.startswith("[") and exp.endswith("]"):
#warn("EVAL: EXP: %s" % exp)
with SubItem(d):
- d.putField("iname", iname)
- d.putField("name", escapedExp)
- d.putField("exp", escapedExp)
+ self.putField("iname", iname)
+ self.putField("name", escapedExp)
+ self.putField("exp", escapedExp)
try:
list = eval(exp)
- d.putValue("")
- d.putType(" ")
- d.putNumChild(len(list))
+ self.putValue("")
+ self.putType(" ")
+ self.putNumChild(len(list))
# This is a list of expressions to evaluate
- with Children(d, len(list)):
+ with Children(self, len(list)):
itemNumber = 0
for item in list:
- self.handleWatch(d, item, "%s.%d" % (iname, itemNumber))
+ self.handleWatch(item, "%s.%d" % (iname, itemNumber))
itemNumber += 1
except RuntimeError, error:
warn("EVAL: ERROR CAUGHT %s" % error)
- d.putValue("<syntax error>")
- d.putType(" ")
- d.putNumChild(0)
- with Children(d, 0):
+ self.putValue("<syntax error>")
+ self.putType(" ")
+ self.putNumChild(0)
+ with Children(self, 0):
pass
return
- with SubItem(d):
- d.putField("iname", iname)
- d.putField("name", escapedExp)
- d.putField("exp", escapedExp)
+ with SubItem(self):
+ self.putField("iname", iname)
+ self.putField("name", escapedExp)
+ self.putField("exp", escapedExp)
handled = False
if exp == "<Edit>" or len(exp) == 0:
- d.put('value=" ",type=" ",numchild="0",')
+ self.put('value=" ",type=" ",numchild="0",')
else:
try:
value = parseAndEvaluate(exp)
item = Item(value, iname, None, None)
if not value is None:
- d.putAddress(value.address)
- d.putItemHelper(item)
+ self.putAddress(value.address)
+ self.putItemHelper(item)
except RuntimeError:
- d.put('value="<invalid>",type="<unknown>",numchild="0",')
-
-
-FrameCommand()
-
-
-#######################################################################
-#
-# Step Command
-#
-#######################################################################
-
-
-class SalCommand(gdb.Command):
- """Do fancy stuff."""
-
- def __init__(self):
- super(SalCommand, self).__init__("sal", gdb.COMMAND_OBSCURE)
-
- def invoke(self, arg, from_tty):
- (cmd, addr) = arg.split(",")
- lines = catchCliOutput("info line *" + addr)
- fromAddr = "0x0"
- toAddr = "0x0"
- for line in lines:
- pos0from = line.find(" starts at address") + 19
- pos1from = line.find(" ", pos0from)
- pos0to = line.find(" ends at", pos1from) + 9
- pos1to = line.find(" ", pos0to)
- if pos1to > 0:
- fromAddr = line[pos0from : pos1from]
- toAddr = line[pos0to : pos1to]
- gdb.execute("maint packet sal%s,%s,%s" % (cmd,fromAddr, toAddr))
-
-SalCommand()
-
+ self.put('value="<invalid>",type="<unknown>",numchild="0",')
-#######################################################################
-#
-# The Dumper Class
-#
-#######################################################################
-
-
-class Dumper:
- def __init__(self):
- self.output = ""
- self.currentChildType = ""
- self.currentChildNumChild = -1
- self.currentMaxNumChilds = -1
- self.currentNumChilds = -1
- self.currentValue = None
- self.currentValuePriority = -100
- self.currentValueEncoding = None
- self.currentType = None
- self.currentTypePriority = -100
def put(self, value):
self.output += value
def putPointerValue(self, value):
# Use a lower priority
self.putValue("0x%x" % value.dereference().cast(
- gdb.lookup_type("unsigned long")), None, -1)
+ lookupType("unsigned long")), None, -1)
def putStringValue(self, value):
if value is None:
self.putNumChild(1)
if self.isExpanded(item):
with Children(self):
- self.putItem(
- Item(item.value.dereference(), item.iname, "*", "*"))
+ with SubItem(self):
+ self.putItemHelper(Item(item.value.dereference(),
+ item.iname, "*", "*"))
+ self.putAddress(item.value)
self.putPointerValue(value.address)
elif str(type).startswith("<anon"):
if self.isExpanded(item):
if value.type.code == gdb.TYPE_CODE_ARRAY:
baseptr = value.cast(value.type.target().pointer())
- charptr = gdb.lookup_type("unsigned char").pointer()
+ charptr = lookupType("unsigned char").pointer()
addr1 = (baseptr+1).cast(charptr)
addr0 = baseptr.cast(charptr)
self.putField("addrbase", cleanAddress(addr0))
#ifdef MACROSDEBUG
Q_DECL_EXPORT char xDumpInBuffer[10000];
Q_DECL_EXPORT char xDumpOutBuffer[1000000];
- #define inBuffer xDumpInBuffer
- #define outBuffer xDumpOutBuffer
+# define inBuffer xDumpInBuffer
+# define outBuffer xDumpOutBuffer
#else
Q_DECL_EXPORT char qDumpInBuffer[10000];
Q_DECL_EXPORT char qDumpOutBuffer[1000000];
- #define inBuffer qDumpInBuffer
- #define outBuffer qDumpOutBuffer
+# define inBuffer qDumpInBuffer
+# define outBuffer qDumpOutBuffer
#endif
namespace {
}
break;
case 'O':
- #ifndef QT_BOOTSTRAPPED
+# ifndef QT_BOOTSTRAPPED
if (isEqual(type, "QObject *")) {
if (addr) {
const QObject *ob = reinterpret_cast<const QObject *>(addr);
d.putItem("numchild", 0);
}
}
- #endif
+# endif
break;
case 'S':
if (isEqual(type, "QString")) {
d.putHash("isNull", date.isNull());
d.putHash("toTime_t", (long)date.toTime_t());
d.putHash("toString", date.toString());
- #if QT_VERSION >= 0x040500
+# if QT_VERSION >= 0x040500
d.putHash("toString_(ISO)", date.toString(Qt::ISODate));
d.putHash("toString_(SystemLocale)", date.toString(Qt::SystemLocaleDate));
d.putHash("toString_(Locale)", date.toString(Qt::LocaleDate));
- #endif
+# endif
- #if 0
+# if 0
d.beginHash();
d.putItem("name", "toUTC");
d.putItem("exp", "(("NSX"QDateTime"NSY"*)").put(d.data).put(")"
d.putItem("type", NS"QDateTime");
d.putItem("numchild", "1");
d.endHash();
- #endif
+# endif
- #if 0
+# if 0
d.beginHash();
d.putItem("name", "toLocalTime");
d.putItem("exp", "(("NSX"QDateTime"NSY"*)").put(d.data).put(")"
d.putItem("type", NS"QDateTime");
d.putItem("numchild", "1");
d.endHash();
- #endif
+# endif
d.endChildren();
}
d.put("(").put(im.width()).put("x").put(im.height()).put(")");
d.endItem();
d.putItem("type", NS"QImage");
- d.putItem("numchild", "1");
+ d.putItem("numchild", "0");
+#if 0
if (d.dumpChildren) {
d.beginChildren();
d.beginHash();
d.endHash();
d.endChildren();
}
+#endif
d.disarm();
}
#endif
*value = QLatin1Char('"') + v->toString() + QLatin1Char('"');
*numchild = 0;
break;
- #if QT_VERSION >= 0x040500
+# if QT_VERSION >= 0x040500
case QVariant::StringList:
*exp = QString(QLatin1String("(*('"NS"QStringList'*)%1)"))
.arg((quintptr)v);
*numchild = v->toStringList().size();
break;
- #endif
+# endif
case QVariant::Int:
*value = QString::number(v->toInt());
*numchild= 0;
*value = QString::number(v->toDouble());
*numchild = 0;
break;
- #ifndef QT_BOOTSTRAPPED
+# ifndef QT_BOOTSTRAPPED
case QVariant::Point: {
const QPoint p = v->toPoint();
*value = QString::fromLatin1("%1, %2").arg(p.x()).arg(p.y());
}
*numchild = 0;
break;
- #endif // QT_BOOTSTRAPPED
- #if USE_QT_GUI
+# endif // QT_BOOTSTRAPPED
+# if USE_QT_GUI
case QVariant::Font:
*value = qvariant_cast<QFont>(*v).toString();
break;
*value = qvariant_cast<QColor>(*v).name();
break;
case QVariant::KeySequence:
- #ifndef QT_NO_SHORTCUT
+# ifndef QT_NO_SHORTCUT
*value = qvariant_cast<QKeySequence>(*v).toString();
- #else
+# else
*value = QString::fromLatin1("Disabled by QT_NO_SHORTCUT");
- #endif
+# endif
break;
case QVariant::SizePolicy:
*value = sizePolicyValue(qvariant_cast<QSizePolicy>(*v));
break;
- #endif
+# endif
default: {
static const char *qTypeFormat = sizeof(void *) == sizeof(long)
? "'"NS"%s "NS"qVariantValue<"NS"%s >'(*('"NS"QVariant'*)0x%lx)"
#endif // QT_VERSION >= 0x040500
#endif // QT_BOOTSTRAPPED
+static void qDumpQSize(QDumper &d)
+{
+ const QSize s = *reinterpret_cast<const QSize *>(d.data);
+ d.beginItem("value");
+ d.put("(").put(s.width()).put("x").put(s.height()).put(")");
+ d.endItem();
+ d.putItem("type", NS"QSize");
+ d.putItem("numchild", "2");
+ if (d.dumpChildren) {
+ d.beginChildren();
+ d.putHash("w", s.width());
+ d.putHash("h", s.height());
+ d.endChildren();
+ }
+ d.disarm();
+}
+
+static void qDumpQSizeF(QDumper &d)
+{
+ const QSizeF s = *reinterpret_cast<const QSizeF *>(d.data);
+ d.beginItem("value");
+ d.put("(").put(s.width()).put("x").put(s.height()).put(")");
+ d.endItem();
+ d.putItem("type", NS"QSizeF");
+ d.putItem("numchild", "2");
+ if (d.dumpChildren) {
+ d.beginChildren();
+ d.putHash("w", s.width());
+ d.putHash("h", s.height());
+ d.endChildren();
+ }
+ d.disarm();
+}
+
static void qDumpQString(QDumper &d)
{
//qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
qDumpStdMap(d);
break;
case 'A':
- #ifndef QT_BOOTSTRAPPED
+# ifndef QT_BOOTSTRAPPED
if (isEqual(type, "QAbstractItemModel"))
qDumpQAbstractItemModel(d);
else if (isEqual(type, "QAbstractItem"))
qDumpQAbstractItem(d);
- #endif
+# endif
break;
case 'B':
if (isEqual(type, "QByteArray"))
qDumpStdSet(d);
break;
case 'F':
- #ifndef QT_BOOTSTRAPPED
+# ifndef QT_BOOTSTRAPPED
if (isEqual(type, "QFile"))
qDumpQFile(d);
else if (isEqual(type, "QFileInfo"))
qDumpQFileInfo(d);
- #endif
+# endif
break;
case 'H':
if (isEqual(type, "QHash"))
qDumpStdList(d);
break;
case 'I':
- #if USE_QT_GUI
+# if USE_QT_GUI
if (isEqual(type, "QImage"))
qDumpQImage(d);
else if (isEqual(type, "QImageData"))
qDumpQImageData(d);
- #endif
+# endif
break;
case 'L':
- #ifndef QT_BOOTSTRAPPED
+# ifndef QT_BOOTSTRAPPED
if (isEqual(type, "QList"))
qDumpQList(d);
else if (isEqual(type, "QLinkedList"))
qDumpQLinkedList(d);
else if (isEqual(type, "QLocale"))
qDumpQLocale(d);
- #endif
+# endif
break;
case 'M':
- #ifndef QT_BOOTSTRAPPED
+# ifndef QT_BOOTSTRAPPED
if (isEqual(type, "QMap"))
qDumpQMap(d);
else if (isEqual(type, "QMapNode"))
qDumpQModelIndex(d);
else if (isEqual(type, "QMultiMap"))
qDumpQMultiMap(d);
- #endif
+# endif
break;
case 'O':
- #ifndef QT_BOOTSTRAPPED
+# ifndef QT_BOOTSTRAPPED
if (isEqual(type, "QObject"))
qDumpQObject(d);
else if (isEqual(type, "QObjectPropertyList"))
qDumpQObjectSlotList(d);
else if (isEqual(type, "QObjectChildList"))
qDumpQObjectChildList(d);
- #endif
+# endif
break;
case 'P':
- #if USE_QT_GUI
+# if USE_QT_GUI
if (isEqual(type, "QPixmap"))
qDumpQPixmap(d);
- #endif
- #ifndef QT_BOOTSTRAPPED
+# endif
+# ifndef QT_BOOTSTRAPPED
if (isEqual(type, "QPoint"))
qDumpQPoint(d);
else if (isEqual(type, "QPointF"))
qDumpQPointF(d);
- #endif
+# endif
break;
case 'R':
- #ifndef QT_BOOTSTRAPPED
+# ifndef QT_BOOTSTRAPPED
if (isEqual(type, "QRect"))
qDumpQRect(d);
else if (isEqual(type, "QRectF"))
qDumpQRectF(d);
- #endif
+# endif
break;
case 'S':
if (isEqual(type, "QString"))
qDumpQString(d);
else if (isEqual(type, "QStringList"))
qDumpQStringList(d);
- #ifndef QT_BOOTSTRAPPED
+# ifndef QT_BOOTSTRAPPED
else if (isEqual(type, "QSet"))
qDumpQSet(d);
else if (isEqual(type, "QStack"))
qDumpQVector(d);
- #if QT_VERSION >= 0x040500
+# if QT_VERSION >= 0x040500
else if (isEqual(type, "QSharedPointer"))
qDumpQSharedPointer(d);
- #endif
- #endif // QT_BOOTSTRAPPED
+# endif
+# endif // QT_BOOTSTRAPPED
+ else if (isEqual(type, "QSize"))
+ qDumpQSize(d);
+ else if (isEqual(type, "QSizeF"))
+ qDumpQSizeF(d);
break;
case 's':
if (isEqual(type, "wstring"))
qDumpStdWString(d);
break;
case 'T':
- #ifndef QT_BOOTSTRAPPED
+# ifndef QT_BOOTSTRAPPED
if (isEqual(type, "QTextCodec"))
qDumpQTextCodec(d);
- #endif
+# endif
break;
case 'V':
- #ifndef QT_BOOTSTRAPPED
+# ifndef QT_BOOTSTRAPPED
if (isEqual(type, "QVariantList")) { // resolve typedef
d.outerType = "QList";
d.innerType = "QVariant";
} else if (isEqual(type, "QVector")) {
qDumpQVector(d);
}
- #endif
+# endif
break;
case 'W':
- #ifndef QT_BOOTSTRAPPED
- #if QT_VERSION >= 0x040500
+# ifndef QT_BOOTSTRAPPED
+# if QT_VERSION >= 0x040500
if (isEqual(type, "QWeakPointer"))
qDumpQWeakPointer(d);
- #endif
- #endif
+# endif
+# endif
break;
}
"\""NS"QFileInfo\","
"\""NS"QHash\","
"\""NS"QHashNode\","
- //"\""NS"QImage\","
+ "\""NS"QImage\","
//"\""NS"QImageData\","
"\""NS"QLinkedList\","
"\""NS"QList\","
"\""NS"QRectF\","
//"\""NS"QRegion\","
"\""NS"QSet\","
+ "\""NS"QSize\","
+ "\""NS"QSizeF\","
"\""NS"QStack\","
"\""NS"QString\","
"\""NS"QStringList\","
"\""NS"QWeakPointer\","
#endif
#if USE_QT_GUI
+ "\""NS"QPixmap\","
"\""NS"QWidget\","
#endif
#ifdef Q_OS_WIN
}
else {
- #ifndef QT_BOOTSTRAPPED
+# ifndef QT_BOOTSTRAPPED
qDebug() << "Unsupported protocol version" << protocolVersion;
- #endif
+# endif
}
return outBuffer;
}
d.putNumChild(size)
if d.isExpanded(item):
- innerType = gdb.lookup_type("char")
+ innerType = lookupType("char")
with Children(d, [size, 1000], innerType):
data = d_ptr['data']
p = gdb.Value(data.cast(innerType.pointer()))
d.putNumChild(rowCount * columnCount)
if d.isExpanded(item):
with Children(d):
- innerType = gdb.lookup_type(d.ns + "QAbstractItem")
+ innerType = lookupType(d.ns + "QAbstractItem")
for row in xrange(rowCount):
for column in xrange(columnCount):
with SubItem(d):
d.putStringValue(call(item.value, "filePath()"))
d.putNumChild(3)
if d.isExpanded(item):
- with Children(d, 10, gdb.lookup_type(d.ns + "QString")):
+ with Children(d, 10, lookupType(d.ns + "QString")):
d.putCallItem("absolutePath", item, "absolutePath()")
d.putCallItem("absoluteFilePath", item, "absoluteFilePath()")
d.putCallItem("canonicalPath", item, "canonicalPath()")
d.putItemHelper(Item(value, item.iname, "value"))
+def qdump__QHostAddress(d, item):
+ data = item.value["d"]["d"].dereference()
+ d.putStringValue(data["ipString"])
+ d.putNumChild(1)
+ if d.isExpanded(item):
+ with Children(d):
+ d.putFields(Item(data, item.iname))
+
+
def qdump__QList(d, item):
d_ptr = item.value["d"]
begin = d_ptr["begin"]
# in the frontend.
# So as first approximation only do the 'isLarge' check:
isInternal = innerSize <= d_ptr.type.sizeof and d.isMovableType(innerType)
- dummyType = gdb.lookup_type("void").pointer().pointer()
+ dummyType = lookupType("void").pointer().pointer()
innerTypePointer = innerType.pointer()
p = gdb.Value(array).cast(dummyType) + begin
if innerTypeIsPointer:
d.put("%08x" % int(d_ptr["width"]))
d.put("%08x" % int(d_ptr["height"]))
d.put("%08x" % int(d_ptr["format"]))
- p = bits.cast(gdb.lookup_type("unsigned int").pointer())
+ p = bits.cast(lookupType("unsigned int").pointer())
for i in xrange(nbytes / 4):
d.put("%08x" % int(p.dereference()))
p += 1
# Write to an external file. Much faster ;-(
file = tempfile.mkstemp(prefix="gdbpy_")
filename = file[1].replace("\\", "\\\\")
- p = bits.cast(gdb.lookup_type("unsigned char").pointer())
+ p = bits.cast(lookupType("unsigned char").pointer())
gdb.execute("dump binary memory %s %s %s" %
(filename, cleanAddress(p), cleanAddress(p + nbytes)))
d.putDisplay(DisplayImage, " %d %d %d %s"
d.putStringValue(call(item.value, "name()"))
d.putNumChild(8)
if d.isExpanded(item):
- with Children(d, 1, gdb.lookup_type(d.ns + "QChar"), 0):
+ with Children(d, 1, lookupType(d.ns + "QChar"), 0):
d.putCallItem("country", item, "country()")
d.putCallItem("language", item, "language()")
d.putCallItem("measurementSystem", item, "measurementSystem()")
# QMapPayloadNode is QMapNode except for the 'forward' member, so
# its size is most likely the offset of the 'forward' member therein.
# Or possibly 2 * sizeof(void *)
- nodeType = gdb.lookup_type(d.ns + "QMapNode<%s, %s>" % (keyType, valueType))
- payloadSize = nodeType.sizeof - 2 * gdb.lookup_type("void").pointer().sizeof
- charPtr = gdb.lookup_type("char").pointer()
+ nodeType = lookupType(d.ns + "QMapNode<%s, %s>" % (keyType, valueType))
+ payloadSize = nodeType.sizeof - 2 * lookupType("void").pointer().sizeof
+ charPtr = lookupType("char").pointer()
innerType = select(isSimpleKey and isSimpleValue, valueType, nodeType)
# superData = superData.dereference()["d"]["superdata"]
# warn("SUPERDATA: %s" % superData)
- privateType = gdb.lookup_type(d.ns + "QObjectPrivate").pointer()
+ privateType = lookupType(d.ns + "QObjectPrivate").pointer()
d_ptr = item.value["d_ptr"]["d"].cast(privateType).dereference()
#warn("D_PTR: %s " % d_ptr)
objectName = d_ptr["objectName"]
#warn("MO.D: %s " % mo["d"])
metaData = mo["d"]["data"]
metaStringData = mo["d"]["stringdata"]
+ #extradata = mo["d"]["extradata"] # Capitalization!
#warn("METADATA: %s " % metaData)
#warn("STRINGDATA: %s " % metaStringData)
#warn("TYPE: %s " % item.value.type)
# Properties.
with SubItem(d):
- #propertyCount = metaData[6]
+ # Prolog
+ extraData = d_ptr["extraData"] # Capitalization!
+ if isNull(extraData):
+ dynamicPropertyCount = 0
+ else:
+ extraDataType = lookupType(
+ d.ns + "QObjectPrivate::ExtraData").pointer()
+ extraData = extraData.cast(extraDataType)
+ ed = extraData.dereference()
+ names = ed["propertyNames"]
+ values = ed["propertyValues"]
+ #userData = ed["userData"]
+ namesBegin = names["d"]["begin"]
+ namesEnd = names["d"]["end"]
+ namesArray = names["d"]["array"]
+ dynamicPropertyCount = namesEnd - namesBegin
+
+ #staticPropertyCount = metaData[6]
# FIXME: Replace with plain memory accesses.
- propertyCount = call(mo, "propertyCount()")
- #warn("PROPERTY COUNT: %s" % propertyCount)
- propertyData = metaData[7]
+ staticPropertyCount = call(mo, "propertyCount()")
+ #warn("PROPERTY COUNT: %s" % staticPropertyCount)
+ propertyCount = staticPropertyCount + dynamicPropertyCount
+
d.putName("properties")
- d.putItemCount(propertyCount)
d.putType(" ")
+ d.putItemCount(propertyCount)
d.putNumChild(propertyCount)
+
if d.isExpandedIName(item.iname + ".properties"):
- with Children(d):
- for property in xrange(propertyCount):
+ with Children(d, [propertyCount, 500]):
+ # Dynamic properties.
+ dummyType = lookupType("void").pointer().pointer()
+ namesType = lookupType(d.ns + "QByteArray")
+ valuesBegin = values["d"]["begin"]
+ valuesEnd = values["d"]["end"]
+ valuesArray = values["d"]["array"]
+ valuesType = lookupType(d.ns + "QVariant")
+ p = namesArray.cast(dummyType) + namesBegin
+ q = valuesArray.cast(dummyType) + valuesBegin
+ for i in xrange(dynamicPropertyCount):
with SubItem(d):
- offset = propertyData + 3 * property
+ pp = p.cast(namesType.pointer()).dereference();
+ d.putField("key", encodeByteArray(pp))
+ d.putField("keyencoded", Hex2EncodedLatin1)
+ qq = q.cast(valuesType.pointer().pointer())
+ qq = qq.dereference();
+ d.putField("addr", cleanAddress(qq))
+ d.putField("exp", "*('%sQVariant'*)%s"
+ % (d.ns, cleanAddress(qq)))
+ name = "%s.properties.%d" % (item.iname, i)
+ t = qdump__QVariant(d, Item(qq, name))
+ # Override the "QVariant (foo)" output
+ d.putType(t, d.currentTypePriority + 1)
+ p += 1
+ q += 1
+
+ # Static properties.
+ propertyData = metaData[7]
+ for i in xrange(staticPropertyCount):
+ with SubItem(d):
+ offset = propertyData + 3 * i
propertyName = extractCString(metaStringData, metaData[offset])
propertyType = extractCString(metaStringData, metaData[offset + 1])
d.putName(propertyName)
if len(inner):
# Build-in types.
d.putType(inner)
+ name = "%s.properties.%d" % (item.iname, i + dynamicPropertyCount)
d.putItemHelper(Item(val, item.iname + ".properties",
propertyName, propertyName))
# type = type[type.find('"') + 1 : type.rfind('"')]
# type = type.replace("Q", d.ns + "Q") # HACK!
# data = call(item.value, "constData()")
- # tdata = data.cast(gdb.lookup_type(type).pointer()).dereference()
+ # tdata = data.cast(lookupType(type).pointer()).dereference()
# d.putValue("(%s)" % tdata.type)
# d.putType(tdata.type)
# d.putNumChild(1)
d.putValue("...")
d.putNumChild(0)
-
- # connections
+ # Connections.
with SubItem(d):
connectionCount = 0
d.putName("connections")
def qdump__QString(d, item):
d.putStringValue(item.value)
d.putNumChild(0)
+ d.putField("typeformats", "Normal,Displayed");
+ format = d.itemFormat(item)
+ if format == 0:
+ d.putDisplay(StopDisplay)
+ elif format == 1:
+ d.putField("editformat", 2)
+ str = encodeString(item.value)
+ d.putField("editvalue", str)
def qdump__QStringList(d, item):
d.putItemCount(size)
d.putNumChild(size)
if d.isExpanded(item):
- innerType = gdb.lookup_type(d.ns + "QString")
+ innerType = lookupType(d.ns + "QString")
ptr = gdb.Value(d_ptr["array"]).cast(innerType.pointer())
ptr += d_ptr["begin"]
with Children(d, [size, 1000], innerType):
inner = d.ns + "QQuadernion"
if len(inner):
- innerType = gdb.lookup_type(inner)
- sizePD = gdb.lookup_type(d.ns + 'QVariant::Private::Data').sizeof
+ innerType = lookupType(inner)
+ sizePD = lookupType(d.ns + 'QVariant::Private::Data').sizeof
if innerType.sizeof > sizePD:
- sizePS = gdb.lookup_type(d.ns + 'QVariant::PrivateShared').sizeof
- val = (sizePS + data.cast(gdb.lookup_type('char').pointer())) \
+ sizePS = lookupType(d.ns + 'QVariant::PrivateShared').sizeof
+ val = (sizePS + data.cast(lookupType('char').pointer())) \
.cast(innerType.pointer()).dereference()
else:
val = data.cast(innerType)
#warn("VARIANT DATA: '%s' '%s' '%s': " % (val, inner, innert))
if len(inner):
- innerType = gdb.lookup_type(inner)
+ innerType = lookupType(inner)
# FIXME: Why "shared"?
if innerType.sizeof > item.value["d"]["data"].type.sizeof:
v = item.value["d"]["data"]["shared"]["ptr"] \
v = item.value["d"]["data"].cast(innerType)
d.putItemHelper(Item(v, item.iname))
d.putType("%sQVariant (%s)" % (d.ns, innert), d.currentTypePriority + 1)
+ return innert
else:
# User types.
d_member = item.value["d"]
type = type[type.find('"') + 1 : type.rfind('"')]
type = type.replace("Q", d.ns + "Q") # HACK!
data = call(item.value, "constData()")
- tdata = data.cast(gdb.lookup_type(type).pointer()).dereference()
+ tdata = data.cast(lookupType(type).pointer()).dereference()
d.putType("%sQVariant (%s)" % (d.ns, tdata.type))
d.putNumChild(1)
if d.isExpanded(item):
with Children(d):
d.putItem(Item(tdata, item.iname, "data", "data"))
+ return tdata.type
def qdump__QVector(d, item):
data = item.value["_M_dataplus"]["_M_p"]
baseType = item.value.type.unqualified().strip_typedefs()
charType = baseType.template_argument(0)
- repType = gdb.lookup_type("%s::_Rep" % baseType).pointer()
+ repType = lookupType("%s::_Rep" % baseType).pointer()
rep = (data.cast(repType) - 1).dereference()
size = rep['_M_length']
alloc = rep['_M_capacity']
#######################################################################
if False:
+
+ # FIXME: Make that work
+ def qdump__Color(d, item):
+ v = item.value
+ d.putValue("(%s, %s, %s; %s)" % (v["r"], v["g"], v["b"], v["a"]))
+ if d.isExpanded(item):
+ with Children(d):
+ d.putItem(Item(v["r"], item.iname, "0", "r"))
+ d.putItem(Item(v["g"], item.iname, "1", "g"))
+ d.putItem(Item(v["b"], item.iname, "2", "b"))
+ d.putItem(Item(v["a"], item.iname, "3", "a"))
+
+ def qdump__Color_(d, item):
+ v = item.value
+ d.putValue("(%s, %s, %s; %s)" % (v["r"], v["g"], v["b"], v["a"]))
+ if d.isExpanded(item):
+ with Children(d):
+ with SubItem(d):
+ d.putField("iname", item.iname + ".0")
+ d.putItemHelper(Item(v["r"], item.iname, "0", "r"))
+ with SubItem(d):
+ d.putField("iname", item.iname + ".1")
+ d.putItemHelper(Item(v["g"], item.iname, "1", "g"))
+ with SubItem(d):
+ d.putField("iname", item.iname + ".2")
+ d.putItemHelper(Item(v["b"], item.iname, "2", "b"))
+ with SubItem(d):
+ d.putField("iname", item.iname + ".3")
+ d.putItemHelper(Item(v["a"], item.iname, "3", "a"))
+
+
def qdump__Function(d, item):
min = item.value["min"]
max = item.value["max"]
individualformats = None,
watchers = None):
self.options = options
- self.expanded = expanded
+ self.expandedINames = expanded
self.typeformats = typeformats
self.individualformats = individualformats
self.watchers = watchers
- self.doit()
+ if self.options == "listmodules":
+ self.handleListModules()
+ elif self.options == "listsymbols":
+ self.handleListSymbols(expanded)
+ else:
+ self.handleListVars()
def put(self, value):
sys.stdout.write(value)
t = str(type)
if t.startswith("<type '") and t.endswith("'>"):
t = t[7:-2]
+ if t.startswith("<class '") and t.endswith("'>"):
+ t = t[8:-2]
return t
def putType(self, type, priority = 0):
def putName(self, name):
self.put('name="%s",' % name)
- def isExpanded(self, item):
- #warn("IS EXPANDED: %s in %s" % (item.iname, self.expandedINames))
- if item.iname is None:
- raise "Illegal iname 'None'"
- if item.iname.startswith("None"):
- raise "Illegal iname '%s'" % item.iname
- #warn(" --> %s" % (item.iname in self.expandedINames))
- return item.iname in self.expandedINames
+ def isExpanded(self, iname):
+ #self.warn("IS EXPANDED: %s in %s" % (iname, self.expandedINames))
+ if iname.startswith("None"):
+ raise "Illegal iname '%s'" % iname
+ #self.warn(" --> %s" % (iname in self.expandedINames))
+ return iname in self.expandedINames
def isExpandedIName(self, iname):
return iname in self.expandedINames
tt = self.cleanType(t)
if tt == "module" or tt == "function":
return
+ if str(value).startswith("<class '"):
+ return
+ # FIXME: Should we?
+ if str(value).startswith("<enum-item "):
+ return
self.put("{")
self.putField("iname", iname)
self.putName(name)
self.putType(tt)
- if tt == "list" or tt == "tuple":
+ if tt == "NoneType":
+ self.putValue("None")
+ self.putNumChild(0)
+ elif tt == "list" or tt == "tuple":
self.putItemCount(len(value))
#self.putValue(value)
self.put("children=[")
self.put("{")
self.putType(" ")
self.putValue("%s: %s" % (k, v))
- self.put("children=[")
- self.dumpValue(k, "key", "%s.%d.k" % (iname, i))
- self.dumpValue(v, "value", "%s.%d.v" % (iname, i))
- self.put("]},")
+ if self.isExpanded(iname):
+ self.put("children=[")
+ self.dumpValue(k, "key", "%s.%d.k" % (iname, i))
+ self.dumpValue(v, "value", "%s.%d.v" % (iname, i))
+ self.put("]},")
i += 1
self.put("]")
- elif tt == "module" or tt == "function":
+ elif tt == "class":
+ pass
+ elif tt == "module":
+ pass
+ elif tt == "function":
pass
+ elif str(value).startswith("<enum-item "):
+ # FIXME: Having enums always shown like this is not nice.
+ self.putValue(str(value)[11:-1])
+ self.putNumChild(0)
else:
- self.putValue(value)
+ v = str(value)
+ p = v.find(" object at ")
+ if p > 1:
+ v = "@" + v[p + 11:-1]
+ self.putValue(v)
+ if self.isExpanded(iname):
+ self.put("children=[")
+ for child in dir(value):
+ if child == "__dict__":
+ continue
+ if child == "__doc__":
+ continue
+ if child == "__module__":
+ continue
+ attr = getattr(value, child)
+ if callable(attr):
+ continue
+ try:
+ self.dumpValue(attr, child, "%s.%s" % (iname, child))
+ except:
+ pass
+ self.put("],")
self.put("},")
def warn(self, msg):
self.putField("warning", msg)
- def doit(self):
+ def handleListVars(self):
# Trigger error to get a backtrace.
frame = None
#self.warn("frame: %s" % frame)
n = n + 1
sys.stdout.flush()
+
+ def handleListModules(self):
+ self.put("modules=[");
+ for name in sys.modules:
+ self.put("{")
+ self.putName(name)
+ self.putValue(sys.modules[name])
+ self.put("},")
+ self.put("]")
+ sys.stdout.flush()
+
+ def handleListSymbols(self, module):
+ #self.put("symbols=%s" % dir(sys.modules[module]))
+ self.put("symbols=[");
+ for name in sys.modules:
+ self.put("{")
+ self.putName(name)
+ #self.putValue(sys.modules[name])
+ self.put("},")
+ self.put("]")
+ sys.stdout.flush()
--- /dev/null
+Place syntax definitions files inside this directory.
+Files can be downloaded at http://kate-editor.org/downloads/syntax_highlighting?kateversion=3.2
+Instructions on how to write your own definitions can be found at http://kate-editor.org/article/writing_a_kate_highlighting_xml_file
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<module>
- <type name="QAbstractItemModel" extends="Qt.QtObject">
- <signal name="dataChanged">
- <param name="topLeft" type="QModelIndex"/>
- <param name="bottomRight" type="QModelIndex"/>
- </signal>
- <signal name="headerDataChanged">
- <param name="orientation" type="Qt.Orientation"/>
- <param name="first" type="int"/>
- <param name="last" type="int"/>
- </signal>
- <signal name="layoutChanged"/>
- <signal name="layoutAboutToBeChanged"/>
- <signal name="rowsAboutToBeInserted">
- <param name="parent" type="QModelIndex"/>
- <param name="first" type="int"/>
- <param name="last" type="int"/>
- </signal>
- <signal name="rowsInserted">
- <param name="parent" type="QModelIndex"/>
- <param name="first" type="int"/>
- <param name="last" type="int"/>
- </signal>
- <signal name="rowsAboutToBeRemoved">
- <param name="parent" type="QModelIndex"/>
- <param name="first" type="int"/>
- <param name="last" type="int"/>
- </signal>
- <signal name="rowsRemoved">
- <param name="parent" type="QModelIndex"/>
- <param name="first" type="int"/>
- <param name="last" type="int"/>
- </signal>
- <signal name="columnsAboutToBeInserted">
- <param name="parent" type="QModelIndex"/>
- <param name="first" type="int"/>
- <param name="last" type="int"/>
- </signal>
- <signal name="columnsInserted">
- <param name="parent" type="QModelIndex"/>
- <param name="first" type="int"/>
- <param name="last" type="int"/>
- </signal>
- <signal name="columnsAboutToBeRemoved">
- <param name="parent" type="QModelIndex"/>
- <param name="first" type="int"/>
- <param name="last" type="int"/>
- </signal>
- <signal name="columnsRemoved">
- <param name="parent" type="QModelIndex"/>
- <param name="first" type="int"/>
- <param name="last" type="int"/>
- </signal>
- <signal name="modelAboutToBeReset"/>
- <signal name="modelReset"/>
- <signal name="rowsAboutToBeMoved">
- <param name="sourceParent" type="QModelIndex"/>
- <param name="sourceStart" type="int"/>
- <param name="sourceEnd" type="int"/>
- <param name="destinationParent" type="QModelIndex"/>
- <param name="destinationRow" type="int"/>
- </signal>
- <signal name="rowsMoved">
- <param name="parent" type="QModelIndex"/>
- <param name="start" type="int"/>
- <param name="end" type="int"/>
- <param name="destination" type="QModelIndex"/>
- <param name="row" type="int"/>
- </signal>
- <signal name="columnsAboutToBeMoved">
- <param name="sourceParent" type="QModelIndex"/>
- <param name="sourceStart" type="int"/>
- <param name="sourceEnd" type="int"/>
- <param name="destinationParent" type="QModelIndex"/>
- <param name="destinationColumn" type="int"/>
- </signal>
- <signal name="columnsMoved">
- <param name="parent" type="QModelIndex"/>
- <param name="start" type="int"/>
- <param name="end" type="int"/>
- <param name="destination" type="QModelIndex"/>
- <param name="column" type="int"/>
- </signal>
- <method name="submit" type="bool"/>
- <method name="revert"/>
- </type>
- <type name="QAbstractListModel" extends="QAbstractItemModel"/>
- <type name="QAction" extends="Qt.QtObject">
- <enum name="MenuRole">
- <enumerator name="NoRole" value="0"/>
- <enumerator name="TextHeuristicRole" value="1"/>
- <enumerator name="ApplicationSpecificRole" value="2"/>
- <enumerator name="AboutQtRole" value="3"/>
- <enumerator name="AboutRole" value="4"/>
- <enumerator name="PreferencesRole" value="5"/>
- <enumerator name="QuitRole" value="6"/>
- </enum>
- <enum name="SoftKeyRole">
- <enumerator name="NoSoftKey" value="0"/>
- <enumerator name="PositiveSoftKey" value="1"/>
- <enumerator name="NegativeSoftKey" value="2"/>
- <enumerator name="SelectSoftKey" value="3"/>
- </enum>
- <enum name="Priority">
- <enumerator name="LowPriority" value="0"/>
- <enumerator name="NormalPriority" value="128"/>
- <enumerator name="HighPriority" value="256"/>
- </enum>
- <property name="checkable" type="bool"/>
- <property name="checked" type="bool"/>
- <property name="enabled" type="bool"/>
- <property name="icon" type="QIcon"/>
- <property name="text" type="string"/>
- <property name="iconText" type="string"/>
- <property name="toolTip" type="string"/>
- <property name="statusTip" type="string"/>
- <property name="whatsThis" type="string"/>
- <property name="font" type="QFont"/>
- <property name="shortcut" type="QKeySequence"/>
- <property name="shortcutContext" type="Qt.ShortcutContext"/>
- <property name="autoRepeat" type="bool"/>
- <property name="visible" type="bool"/>
- <property name="menuRole" type="MenuRole"/>
- <property name="softKeyRole" type="SoftKeyRole"/>
- <property name="iconVisibleInMenu" type="bool"/>
- <property name="priority" type="Priority"/>
- <signal name="changed"/>
- <signal name="triggered">
- <param name="checked" type="bool"/>
- </signal>
- <signal name="triggered"/>
- <signal name="hovered"/>
- <signal name="toggled">
- <param type="bool"/>
- </signal>
- <method name="trigger"/>
- <method name="hover"/>
- <method name="setChecked">
- <param type="bool"/>
- </method>
- <method name="toggle"/>
- <method name="setEnabled">
- <param type="bool"/>
- </method>
- <method name="setDisabled">
- <param name="b" type="bool"/>
- </method>
- <method name="setVisible">
- <param type="bool"/>
- </method>
- </type>
- <type name="QDeclarativeAnchorSet" extends="Qt.QtObject">
- <property name="left" type="QDeclarativeScriptString"/>
- <property name="right" type="QDeclarativeScriptString"/>
- <property name="horizontalCenter" type="QDeclarativeScriptString"/>
- <property name="top" type="QDeclarativeScriptString"/>
- <property name="bottom" type="QDeclarativeScriptString"/>
- <property name="verticalCenter" type="QDeclarativeScriptString"/>
- <property name="baseline" type="QDeclarativeScriptString"/>
- </type>
- <type name="QDeclarativeAnchors" extends="Qt.QtObject">
- <property name="left" type="QDeclarativeAnchorLine"/>
- <property name="right" type="QDeclarativeAnchorLine"/>
- <property name="horizontalCenter" type="QDeclarativeAnchorLine"/>
- <property name="top" type="QDeclarativeAnchorLine"/>
- <property name="bottom" type="QDeclarativeAnchorLine"/>
- <property name="verticalCenter" type="QDeclarativeAnchorLine"/>
- <property name="baseline" type="QDeclarativeAnchorLine"/>
- <property name="margins" type="qreal"/>
- <property name="leftMargin" type="qreal"/>
- <property name="rightMargin" type="qreal"/>
- <property name="horizontalCenterOffset" type="qreal"/>
- <property name="topMargin" type="qreal"/>
- <property name="bottomMargin" type="qreal"/>
- <property name="verticalCenterOffset" type="qreal"/>
- <property name="baselineOffset" type="qreal"/>
- <property name="fill" type="QGraphicsObject"/>
- <property name="centerIn" type="QGraphicsObject"/>
- <signal name="leftChanged"/>
- <signal name="rightChanged"/>
- <signal name="topChanged"/>
- <signal name="bottomChanged"/>
- <signal name="verticalCenterChanged"/>
- <signal name="horizontalCenterChanged"/>
- <signal name="baselineChanged"/>
- <signal name="fillChanged"/>
- <signal name="centerInChanged"/>
- <signal name="leftMarginChanged"/>
- <signal name="rightMarginChanged"/>
- <signal name="topMarginChanged"/>
- <signal name="bottomMarginChanged"/>
- <signal name="marginsChanged"/>
- <signal name="verticalCenterOffsetChanged"/>
- <signal name="horizontalCenterOffsetChanged"/>
- <signal name="baselineOffsetChanged"/>
- </type>
- <type name="QDeclarativeAnimationGroup" defaultProperty="animations" extends="Qt.Animation">
- <property name="animations" type="Qt.Animation" isList="true"/>
- </type>
- <type name="QDeclarativeBasePositioner" defaultProperty="data" extends="Qt.Item">
- <property name="spacing" type="int"/>
- <property name="move" type="Qt.Transition"/>
- <property name="add" type="Qt.Transition"/>
- <signal name="spacingChanged"/>
- <signal name="moveChanged"/>
- <signal name="addChanged"/>
- </type>
- <type name="QDeclarativeCurve" extends="QDeclarativePathElement">
- <property name="x" type="qreal"/>
- <property name="y" type="qreal"/>
- </type>
- <type name="QDeclarativeFlickableVisibleArea" extends="Qt.QtObject">
- <property name="xPosition" type="qreal"/>
- <property name="yPosition" type="qreal"/>
- <property name="widthRatio" type="qreal"/>
- <property name="heightRatio" type="qreal"/>
- <signal name="pageChanged"/>
- </type>
- <type name="QDeclarativeGraphicsWidget" defaultProperty="children" extends="Qt.QGraphicsWidget">
- <property name="anchors" type="QDeclarativeAnchors"/>
- <property name="left" type="QDeclarativeAnchorLine"/>
- <property name="right" type="QDeclarativeAnchorLine"/>
- <property name="horizontalCenter" type="QDeclarativeAnchorLine"/>
- <property name="top" type="QDeclarativeAnchorLine"/>
- <property name="bottom" type="QDeclarativeAnchorLine"/>
- <property name="verticalCenter" type="QDeclarativeAnchorLine"/>
- </type>
- <type name="QDeclarativeImageBase" defaultProperty="data" extends="Qt.Item">
- <enum name="Status">
- <enumerator name="Null" value="0"/>
- <enumerator name="Ready" value="1"/>
- <enumerator name="Loading" value="2"/>
- <enumerator name="Error" value="3"/>
- </enum>
- <property name="status" type="Status"/>
- <property name="source" type="QUrl"/>
- <property name="progress" type="qreal"/>
- <property name="asynchronous" type="bool"/>
- <property name="sourceSize" type="QSize"/>
- <signal name="sourceChanged">
- <param type="QUrl"/>
- </signal>
- <signal name="sourceSizeChanged"/>
- <signal name="statusChanged">
- <param type="Status"/>
- </signal>
- <signal name="progressChanged">
- <param name="progress" type="qreal"/>
- </signal>
- <signal name="asynchronousChanged"/>
- </type>
- <type name="QDeclarativePaintedItem" defaultProperty="data" extends="Qt.Item">
- <property name="contentsSize" type="QSize"/>
- <property name="fillColor" type="QColor"/>
- <property name="pixelCacheSize" type="int"/>
- <property name="smoothCache" type="bool"/>
- <property name="contentsScale" type="qreal"/>
- <signal name="fillColorChanged"/>
- <signal name="contentsSizeChanged"/>
- <signal name="contentsScaleChanged"/>
- </type>
- <type name="QDeclarativePathElement" extends="Qt.QtObject">
- <signal name="changed"/>
- </type>
- <type name="QDeclarativePen" extends="Qt.QtObject">
- <property name="width" type="int"/>
- <property name="color" type="QColor"/>
- <signal name="penChanged"/>
- </type>
- <type name="QDeclarativeScaleGrid" extends="Qt.QtObject">
- <property name="left" type="int"/>
- <property name="top" type="int"/>
- <property name="right" type="int"/>
- <property name="bottom" type="int"/>
- <signal name="borderChanged"/>
- </type>
- <type name="QDeclarativeStateOperation" extends="Qt.QtObject"/>
- <type name="QDeclarativeValueType" extends="Qt.QtObject"/>
- <type name="QDeclarativeVisualDataModelParts" extends="Qt.QtObject"/>
- <type name="QDeclarativeVisualModel" extends="Qt.QtObject">
- <property name="count" type="int"/>
- <signal name="countChanged"/>
- <signal name="itemsInserted">
- <param name="index" type="int"/>
- <param name="count" type="int"/>
- </signal>
- <signal name="itemsRemoved">
- <param name="index" type="int"/>
- <param name="count" type="int"/>
- </signal>
- <signal name="itemsMoved">
- <param name="from" type="int"/>
- <param name="to" type="int"/>
- <param name="count" type="int"/>
- </signal>
- <signal name="modelReset"/>
- <signal name="createdItem">
- <param name="index" type="int"/>
- <param name="item" type="Qt.Item"/>
- </signal>
- <signal name="destroyingItem">
- <param name="item" type="Qt.Item"/>
- </signal>
- </type>
- <type name="QDeclarativeWebSettings" extends="Qt.QtObject">
- <property name="standardFontFamily" type="string"/>
- <property name="fixedFontFamily" type="string"/>
- <property name="serifFontFamily" type="string"/>
- <property name="sansSerifFontFamily" type="string"/>
- <property name="cursiveFontFamily" type="string"/>
- <property name="fantasyFontFamily" type="string"/>
- <property name="minimumFontSize" type="int"/>
- <property name="minimumLogicalFontSize" type="int"/>
- <property name="defaultFontSize" type="int"/>
- <property name="defaultFixedFontSize" type="int"/>
- <property name="autoLoadImages" type="bool"/>
- <property name="javascriptEnabled" type="bool"/>
- <property name="javaEnabled" type="bool"/>
- <property name="pluginsEnabled" type="bool"/>
- <property name="privateBrowsingEnabled" type="bool"/>
- <property name="javascriptCanOpenWindows" type="bool"/>
- <property name="javascriptCanAccessClipboard" type="bool"/>
- <property name="developerExtrasEnabled" type="bool"/>
- <property name="linksIncludedInFocusChain" type="bool"/>
- <property name="zoomTextOnly" type="bool"/>
- <property name="printElementBackgrounds" type="bool"/>
- <property name="offlineStorageDatabaseEnabled" type="bool"/>
- <property name="offlineWebApplicationCacheEnabled" type="bool"/>
- <property name="localStorageDatabaseEnabled" type="bool"/>
- <property name="localContentCanAccessRemoteUrls" type="bool"/>
- </type>
- <type name="QGraphicsObject" defaultProperty="children" extends="Qt.QtObject">
- <property name="parent" type="QGraphicsObject"/>
- <property name="opacity" type="qreal"/>
- <property name="enabled" type="bool"/>
- <property name="visible" type="bool"/>
- <property name="pos" type="QPointF"/>
- <property name="x" type="qreal"/>
- <property name="y" type="qreal"/>
- <property name="z" type="qreal"/>
- <property name="rotation" type="qreal"/>
- <property name="scale" type="qreal"/>
- <property name="transformOriginPoint" type="QPointF"/>
- <property name="effect" type="QGraphicsEffect"/>
- <property name="children" type="QGraphicsObject" isList="true"/>
- <property name="width" type="qreal"/>
- <property name="height" type="qreal"/>
- <signal name="parentChanged"/>
- <signal name="opacityChanged"/>
- <signal name="visibleChanged"/>
- <signal name="enabledChanged"/>
- <signal name="xChanged"/>
- <signal name="yChanged"/>
- <signal name="zChanged"/>
- <signal name="rotationChanged"/>
- <signal name="scaleChanged"/>
- <signal name="childrenChanged"/>
- <signal name="widthChanged"/>
- <signal name="heightChanged"/>
- </type>
- <type name="QGraphicsTransform" extends="Qt.QtObject"/>
- <type name="QListModelInterface" extends="Qt.QtObject">
- <signal name="itemsInserted">
- <param name="index" type="int"/>
- <param name="count" type="int"/>
- </signal>
- <signal name="itemsRemoved">
- <param name="index" type="int"/>
- <param name="count" type="int"/>
- </signal>
- <signal name="itemsMoved">
- <param name="from" type="int"/>
- <param name="to" type="int"/>
- <param name="count" type="int"/>
- </signal>
- <signal name="itemsChanged">
- <param name="index" type="int"/>
- <param name="count" type="int"/>
- <param name="roles" type="QList<int>"/>
- </signal>
- </type>
- <type name="QValidator" extends="Qt.QtObject"/>
- <type name="Qt">
- <enum name="GlobalColor">
- <enumerator name="color0" value="0"/>
- <enumerator name="color1" value="1"/>
- <enumerator name="black" value="2"/>
- <enumerator name="white" value="3"/>
- <enumerator name="darkGray" value="4"/>
- <enumerator name="gray" value="5"/>
- <enumerator name="lightGray" value="6"/>
- <enumerator name="red" value="7"/>
- <enumerator name="green" value="8"/>
- <enumerator name="blue" value="9"/>
- <enumerator name="cyan" value="10"/>
- <enumerator name="magenta" value="11"/>
- <enumerator name="yellow" value="12"/>
- <enumerator name="darkRed" value="13"/>
- <enumerator name="darkGreen" value="14"/>
- <enumerator name="darkBlue" value="15"/>
- <enumerator name="darkCyan" value="16"/>
- <enumerator name="darkMagenta" value="17"/>
- <enumerator name="darkYellow" value="18"/>
- <enumerator name="transparent" value="19"/>
- </enum>
- <enum name="KeyboardModifiers">
- <enumerator name="NoModifier" value="0"/>
- <enumerator name="ShiftModifier" value="33554432"/>
- <enumerator name="ControlModifier" value="67108864"/>
- <enumerator name="AltModifier" value="134217728"/>
- <enumerator name="MetaModifier" value="268435456"/>
- <enumerator name="KeypadModifier" value="536870912"/>
- <enumerator name="GroupSwitchModifier" value="1073741824"/>
- <enumerator name="KeyboardModifierMask" value="-33554432"/>
- </enum>
- <enum name="MouseButtons">
- <enumerator name="NoButton" value="0"/>
- <enumerator name="LeftButton" value="1"/>
- <enumerator name="RightButton" value="2"/>
- <enumerator name="MidButton" value="4"/>
- <enumerator name="MiddleButton" value="4"/>
- <enumerator name="XButton1" value="8"/>
- <enumerator name="XButton2" value="16"/>
- <enumerator name="MouseButtonMask" value="255"/>
- </enum>
- <enum name="Orientation">
- <enumerator name="Horizontal" value="1"/>
- <enumerator name="Vertical" value="2"/>
- </enum>
- <enum name="Orientations">
- <enumerator name="Horizontal" value="1"/>
- <enumerator name="Vertical" value="2"/>
- </enum>
- <enum name="FocusPolicy">
- <enumerator name="NoFocus" value="0"/>
- <enumerator name="TabFocus" value="1"/>
- <enumerator name="ClickFocus" value="2"/>
- <enumerator name="StrongFocus" value="11"/>
- <enumerator name="WheelFocus" value="15"/>
- </enum>
- <enum name="SortOrder">
- <enumerator name="AscendingOrder" value="0"/>
- <enumerator name="DescendingOrder" value="1"/>
- </enum>
- <enum name="Alignment">
- <enumerator name="AlignLeft" value="1"/>
- <enumerator name="AlignLeading" value="1"/>
- <enumerator name="AlignRight" value="2"/>
- <enumerator name="AlignTrailing" value="2"/>
- <enumerator name="AlignHCenter" value="4"/>
- <enumerator name="AlignJustify" value="8"/>
- <enumerator name="AlignAbsolute" value="16"/>
- <enumerator name="AlignHorizontal_Mask" value="31"/>
- <enumerator name="AlignTop" value="32"/>
- <enumerator name="AlignBottom" value="64"/>
- <enumerator name="AlignVCenter" value="128"/>
- <enumerator name="AlignVertical_Mask" value="224"/>
- <enumerator name="AlignCenter" value="132"/>
- </enum>
- <enum name="TextElideMode">
- <enumerator name="ElideLeft" value="0"/>
- <enumerator name="ElideRight" value="1"/>
- <enumerator name="ElideMiddle" value="2"/>
- <enumerator name="ElideNone" value="3"/>
- </enum>
- <enum name="WindowType">
- <enumerator name="Widget" value="0"/>
- <enumerator name="Window" value="1"/>
- <enumerator name="Dialog" value="3"/>
- <enumerator name="Sheet" value="5"/>
- <enumerator name="Drawer" value="7"/>
- <enumerator name="Popup" value="9"/>
- <enumerator name="Tool" value="11"/>
- <enumerator name="ToolTip" value="13"/>
- <enumerator name="SplashScreen" value="15"/>
- <enumerator name="Desktop" value="17"/>
- <enumerator name="SubWindow" value="18"/>
- <enumerator name="WindowType_Mask" value="255"/>
- <enumerator name="MSWindowsFixedSizeDialogHint" value="256"/>
- <enumerator name="MSWindowsOwnDC" value="512"/>
- <enumerator name="X11BypassWindowManagerHint" value="1024"/>
- <enumerator name="FramelessWindowHint" value="2048"/>
- <enumerator name="WindowTitleHint" value="4096"/>
- <enumerator name="WindowSystemMenuHint" value="8192"/>
- <enumerator name="WindowMinimizeButtonHint" value="16384"/>
- <enumerator name="WindowMaximizeButtonHint" value="32768"/>
- <enumerator name="WindowMinMaxButtonsHint" value="49152"/>
- <enumerator name="WindowContextHelpButtonHint" value="65536"/>
- <enumerator name="WindowShadeButtonHint" value="131072"/>
- <enumerator name="WindowStaysOnTopHint" value="262144"/>
- <enumerator name="CustomizeWindowHint" value="33554432"/>
- <enumerator name="WindowStaysOnBottomHint" value="67108864"/>
- <enumerator name="WindowCloseButtonHint" value="134217728"/>
- <enumerator name="MacWindowToolBarButtonHint" value="268435456"/>
- <enumerator name="BypassGraphicsProxyWidget" value="536870912"/>
- <enumerator name="WindowOkButtonHint" value="524288"/>
- <enumerator name="WindowCancelButtonHint" value="1048576"/>
- <enumerator name="WindowSoftkeysVisibleHint" value="1073741824"/>
- <enumerator name="WindowSoftkeysRespondHint" value="-2147483648"/>
- </enum>
- <enum name="WindowFlags">
- <enumerator name="Widget" value="0"/>
- <enumerator name="Window" value="1"/>
- <enumerator name="Dialog" value="3"/>
- <enumerator name="Sheet" value="5"/>
- <enumerator name="Drawer" value="7"/>
- <enumerator name="Popup" value="9"/>
- <enumerator name="Tool" value="11"/>
- <enumerator name="ToolTip" value="13"/>
- <enumerator name="SplashScreen" value="15"/>
- <enumerator name="Desktop" value="17"/>
- <enumerator name="SubWindow" value="18"/>
- <enumerator name="WindowType_Mask" value="255"/>
- <enumerator name="MSWindowsFixedSizeDialogHint" value="256"/>
- <enumerator name="MSWindowsOwnDC" value="512"/>
- <enumerator name="X11BypassWindowManagerHint" value="1024"/>
- <enumerator name="FramelessWindowHint" value="2048"/>
- <enumerator name="WindowTitleHint" value="4096"/>
- <enumerator name="WindowSystemMenuHint" value="8192"/>
- <enumerator name="WindowMinimizeButtonHint" value="16384"/>
- <enumerator name="WindowMaximizeButtonHint" value="32768"/>
- <enumerator name="WindowMinMaxButtonsHint" value="49152"/>
- <enumerator name="WindowContextHelpButtonHint" value="65536"/>
- <enumerator name="WindowShadeButtonHint" value="131072"/>
- <enumerator name="WindowStaysOnTopHint" value="262144"/>
- <enumerator name="CustomizeWindowHint" value="33554432"/>
- <enumerator name="WindowStaysOnBottomHint" value="67108864"/>
- <enumerator name="WindowCloseButtonHint" value="134217728"/>
- <enumerator name="MacWindowToolBarButtonHint" value="268435456"/>
- <enumerator name="BypassGraphicsProxyWidget" value="536870912"/>
- <enumerator name="WindowOkButtonHint" value="524288"/>
- <enumerator name="WindowCancelButtonHint" value="1048576"/>
- <enumerator name="WindowSoftkeysVisibleHint" value="1073741824"/>
- <enumerator name="WindowSoftkeysRespondHint" value="-2147483648"/>
- </enum>
- <enum name="WindowState">
- <enumerator name="WindowNoState" value="0"/>
- <enumerator name="WindowMinimized" value="1"/>
- <enumerator name="WindowMaximized" value="2"/>
- <enumerator name="WindowFullScreen" value="4"/>
- <enumerator name="WindowActive" value="8"/>
- </enum>
- <enum name="WindowStates">
- <enumerator name="WindowNoState" value="0"/>
- <enumerator name="WindowMinimized" value="1"/>
- <enumerator name="WindowMaximized" value="2"/>
- <enumerator name="WindowFullScreen" value="4"/>
- <enumerator name="WindowActive" value="8"/>
- </enum>
- <enum name="WidgetAttribute">
- <enumerator name="WA_Disabled" value="0"/>
- <enumerator name="WA_UnderMouse" value="1"/>
- <enumerator name="WA_MouseTracking" value="2"/>
- <enumerator name="WA_ContentsPropagated" value="3"/>
- <enumerator name="WA_OpaquePaintEvent" value="4"/>
- <enumerator name="WA_NoBackground" value="4"/>
- <enumerator name="WA_StaticContents" value="5"/>
- <enumerator name="WA_LaidOut" value="7"/>
- <enumerator name="WA_PaintOnScreen" value="8"/>
- <enumerator name="WA_NoSystemBackground" value="9"/>
- <enumerator name="WA_UpdatesDisabled" value="10"/>
- <enumerator name="WA_Mapped" value="11"/>
- <enumerator name="WA_MacNoClickThrough" value="12"/>
- <enumerator name="WA_PaintOutsidePaintEvent" value="13"/>
- <enumerator name="WA_InputMethodEnabled" value="14"/>
- <enumerator name="WA_WState_Visible" value="15"/>
- <enumerator name="WA_WState_Hidden" value="16"/>
- <enumerator name="WA_ForceDisabled" value="32"/>
- <enumerator name="WA_KeyCompression" value="33"/>
- <enumerator name="WA_PendingMoveEvent" value="34"/>
- <enumerator name="WA_PendingResizeEvent" value="35"/>
- <enumerator name="WA_SetPalette" value="36"/>
- <enumerator name="WA_SetFont" value="37"/>
- <enumerator name="WA_SetCursor" value="38"/>
- <enumerator name="WA_NoChildEventsFromChildren" value="39"/>
- <enumerator name="WA_WindowModified" value="41"/>
- <enumerator name="WA_Resized" value="42"/>
- <enumerator name="WA_Moved" value="43"/>
- <enumerator name="WA_PendingUpdate" value="44"/>
- <enumerator name="WA_InvalidSize" value="45"/>
- <enumerator name="WA_MacBrushedMetal" value="46"/>
- <enumerator name="WA_MacMetalStyle" value="46"/>
- <enumerator name="WA_CustomWhatsThis" value="47"/>
- <enumerator name="WA_LayoutOnEntireRect" value="48"/>
- <enumerator name="WA_OutsideWSRange" value="49"/>
- <enumerator name="WA_GrabbedShortcut" value="50"/>
- <enumerator name="WA_TransparentForMouseEvents" value="51"/>
- <enumerator name="WA_PaintUnclipped" value="52"/>
- <enumerator name="WA_SetWindowIcon" value="53"/>
- <enumerator name="WA_NoMouseReplay" value="54"/>
- <enumerator name="WA_DeleteOnClose" value="55"/>
- <enumerator name="WA_RightToLeft" value="56"/>
- <enumerator name="WA_SetLayoutDirection" value="57"/>
- <enumerator name="WA_NoChildEventsForParent" value="58"/>
- <enumerator name="WA_ForceUpdatesDisabled" value="59"/>
- <enumerator name="WA_WState_Created" value="60"/>
- <enumerator name="WA_WState_CompressKeys" value="61"/>
- <enumerator name="WA_WState_InPaintEvent" value="62"/>
- <enumerator name="WA_WState_Reparented" value="63"/>
- <enumerator name="WA_WState_ConfigPending" value="64"/>
- <enumerator name="WA_WState_Polished" value="66"/>
- <enumerator name="WA_WState_DND" value="67"/>
- <enumerator name="WA_WState_OwnSizePolicy" value="68"/>
- <enumerator name="WA_WState_ExplicitShowHide" value="69"/>
- <enumerator name="WA_ShowModal" value="70"/>
- <enumerator name="WA_MouseNoMask" value="71"/>
- <enumerator name="WA_GroupLeader" value="72"/>
- <enumerator name="WA_NoMousePropagation" value="73"/>
- <enumerator name="WA_Hover" value="74"/>
- <enumerator name="WA_InputMethodTransparent" value="75"/>
- <enumerator name="WA_QuitOnClose" value="76"/>
- <enumerator name="WA_KeyboardFocusChange" value="77"/>
- <enumerator name="WA_AcceptDrops" value="78"/>
- <enumerator name="WA_DropSiteRegistered" value="79"/>
- <enumerator name="WA_ForceAcceptDrops" value="79"/>
- <enumerator name="WA_WindowPropagation" value="80"/>
- <enumerator name="WA_NoX11EventCompression" value="81"/>
- <enumerator name="WA_TintedBackground" value="82"/>
- <enumerator name="WA_X11OpenGLOverlay" value="83"/>
- <enumerator name="WA_AlwaysShowToolTips" value="84"/>
- <enumerator name="WA_MacOpaqueSizeGrip" value="85"/>
- <enumerator name="WA_SetStyle" value="86"/>
- <enumerator name="WA_SetLocale" value="87"/>
- <enumerator name="WA_MacShowFocusRect" value="88"/>
- <enumerator name="WA_MacNormalSize" value="89"/>
- <enumerator name="WA_MacSmallSize" value="90"/>
- <enumerator name="WA_MacMiniSize" value="91"/>
- <enumerator name="WA_LayoutUsesWidgetRect" value="92"/>
- <enumerator name="WA_StyledBackground" value="93"/>
- <enumerator name="WA_MSWindowsUseDirect3D" value="94"/>
- <enumerator name="WA_CanHostQMdiSubWindowTitleBar" value="95"/>
- <enumerator name="WA_MacAlwaysShowToolWindow" value="96"/>
- <enumerator name="WA_StyleSheet" value="97"/>
- <enumerator name="WA_ShowWithoutActivating" value="98"/>
- <enumerator name="WA_X11BypassTransientForHint" value="99"/>
- <enumerator name="WA_NativeWindow" value="100"/>
- <enumerator name="WA_DontCreateNativeAncestors" value="101"/>
- <enumerator name="WA_MacVariableSize" value="102"/>
- <enumerator name="WA_DontShowOnScreen" value="103"/>
- <enumerator name="WA_X11NetWmWindowTypeDesktop" value="104"/>
- <enumerator name="WA_X11NetWmWindowTypeDock" value="105"/>
- <enumerator name="WA_X11NetWmWindowTypeToolBar" value="106"/>
- <enumerator name="WA_X11NetWmWindowTypeMenu" value="107"/>
- <enumerator name="WA_X11NetWmWindowTypeUtility" value="108"/>
- <enumerator name="WA_X11NetWmWindowTypeSplash" value="109"/>
- <enumerator name="WA_X11NetWmWindowTypeDialog" value="110"/>
- <enumerator name="WA_X11NetWmWindowTypeDropDownMenu" value="111"/>
- <enumerator name="WA_X11NetWmWindowTypePopupMenu" value="112"/>
- <enumerator name="WA_X11NetWmWindowTypeToolTip" value="113"/>
- <enumerator name="WA_X11NetWmWindowTypeNotification" value="114"/>
- <enumerator name="WA_X11NetWmWindowTypeCombo" value="115"/>
- <enumerator name="WA_X11NetWmWindowTypeDND" value="116"/>
- <enumerator name="WA_MacFrameworkScaled" value="117"/>
- <enumerator name="WA_SetWindowModality" value="118"/>
- <enumerator name="WA_WState_WindowOpacitySet" value="119"/>
- <enumerator name="WA_TranslucentBackground" value="120"/>
- <enumerator name="WA_AcceptTouchEvents" value="121"/>
- <enumerator name="WA_WState_AcceptedTouchBeginEvent" value="122"/>
- <enumerator name="WA_TouchPadAcceptSingleTouchEvents" value="123"/>
- <enumerator name="WA_MergeSoftkeys" value="124"/>
- <enumerator name="WA_MergeSoftkeysRecursively" value="125"/>
- <enumerator name="WA_X11DoNotAcceptFocus" value="132"/>
- <enumerator name="WA_AttributeCount" value="133"/>
- </enum>
- <enum name="ApplicationAttribute">
- <enumerator name="AA_ImmediateWidgetCreation" value="0"/>
- <enumerator name="AA_MSWindowsUseDirect3DByDefault" value="1"/>
- <enumerator name="AA_DontShowIconsInMenus" value="2"/>
- <enumerator name="AA_NativeWindows" value="3"/>
- <enumerator name="AA_DontCreateNativeWidgetSiblings" value="4"/>
- <enumerator name="AA_MacPluginApplication" value="5"/>
- <enumerator name="AA_DontUseNativeMenuBar" value="6"/>
- <enumerator name="AA_MacDontSwapCtrlAndMeta" value="7"/>
- <enumerator name="AA_S60DontConstructApplicationPanes" value="8"/>
- <enumerator name="AA_AttributeCount" value="9"/>
- </enum>
- <enum name="ImageConversionFlags">
- <enumerator name="ColorMode_Mask" value="3"/>
- <enumerator name="AutoColor" value="0"/>
- <enumerator name="ColorOnly" value="3"/>
- <enumerator name="MonoOnly" value="2"/>
- <enumerator name="AlphaDither_Mask" value="12"/>
- <enumerator name="ThresholdAlphaDither" value="0"/>
- <enumerator name="OrderedAlphaDither" value="4"/>
- <enumerator name="DiffuseAlphaDither" value="8"/>
- <enumerator name="NoAlpha" value="12"/>
- <enumerator name="Dither_Mask" value="48"/>
- <enumerator name="DiffuseDither" value="0"/>
- <enumerator name="OrderedDither" value="16"/>
- <enumerator name="ThresholdDither" value="32"/>
- <enumerator name="DitherMode_Mask" value="192"/>
- <enumerator name="AutoDither" value="0"/>
- <enumerator name="PreferDither" value="64"/>
- <enumerator name="AvoidDither" value="128"/>
- <enumerator name="NoOpaqueDetection" value="256"/>
- </enum>
- <enum name="BGMode">
- <enumerator name="TransparentMode" value="0"/>
- <enumerator name="OpaqueMode" value="1"/>
- </enum>
- <enum name="Key">
- <enumerator name="Key_Escape" value="16777216"/>
- <enumerator name="Key_Tab" value="16777217"/>
- <enumerator name="Key_Backtab" value="16777218"/>
- <enumerator name="Key_Backspace" value="16777219"/>
- <enumerator name="Key_Return" value="16777220"/>
- <enumerator name="Key_Enter" value="16777221"/>
- <enumerator name="Key_Insert" value="16777222"/>
- <enumerator name="Key_Delete" value="16777223"/>
- <enumerator name="Key_Pause" value="16777224"/>
- <enumerator name="Key_Print" value="16777225"/>
- <enumerator name="Key_SysReq" value="16777226"/>
- <enumerator name="Key_Clear" value="16777227"/>
- <enumerator name="Key_Home" value="16777232"/>
- <enumerator name="Key_End" value="16777233"/>
- <enumerator name="Key_Left" value="16777234"/>
- <enumerator name="Key_Up" value="16777235"/>
- <enumerator name="Key_Right" value="16777236"/>
- <enumerator name="Key_Down" value="16777237"/>
- <enumerator name="Key_PageUp" value="16777238"/>
- <enumerator name="Key_PageDown" value="16777239"/>
- <enumerator name="Key_Shift" value="16777248"/>
- <enumerator name="Key_Control" value="16777249"/>
- <enumerator name="Key_Meta" value="16777250"/>
- <enumerator name="Key_Alt" value="16777251"/>
- <enumerator name="Key_CapsLock" value="16777252"/>
- <enumerator name="Key_NumLock" value="16777253"/>
- <enumerator name="Key_ScrollLock" value="16777254"/>
- <enumerator name="Key_F1" value="16777264"/>
- <enumerator name="Key_F2" value="16777265"/>
- <enumerator name="Key_F3" value="16777266"/>
- <enumerator name="Key_F4" value="16777267"/>
- <enumerator name="Key_F5" value="16777268"/>
- <enumerator name="Key_F6" value="16777269"/>
- <enumerator name="Key_F7" value="16777270"/>
- <enumerator name="Key_F8" value="16777271"/>
- <enumerator name="Key_F9" value="16777272"/>
- <enumerator name="Key_F10" value="16777273"/>
- <enumerator name="Key_F11" value="16777274"/>
- <enumerator name="Key_F12" value="16777275"/>
- <enumerator name="Key_F13" value="16777276"/>
- <enumerator name="Key_F14" value="16777277"/>
- <enumerator name="Key_F15" value="16777278"/>
- <enumerator name="Key_F16" value="16777279"/>
- <enumerator name="Key_F17" value="16777280"/>
- <enumerator name="Key_F18" value="16777281"/>
- <enumerator name="Key_F19" value="16777282"/>
- <enumerator name="Key_F20" value="16777283"/>
- <enumerator name="Key_F21" value="16777284"/>
- <enumerator name="Key_F22" value="16777285"/>
- <enumerator name="Key_F23" value="16777286"/>
- <enumerator name="Key_F24" value="16777287"/>
- <enumerator name="Key_F25" value="16777288"/>
- <enumerator name="Key_F26" value="16777289"/>
- <enumerator name="Key_F27" value="16777290"/>
- <enumerator name="Key_F28" value="16777291"/>
- <enumerator name="Key_F29" value="16777292"/>
- <enumerator name="Key_F30" value="16777293"/>
- <enumerator name="Key_F31" value="16777294"/>
- <enumerator name="Key_F32" value="16777295"/>
- <enumerator name="Key_F33" value="16777296"/>
- <enumerator name="Key_F34" value="16777297"/>
- <enumerator name="Key_F35" value="16777298"/>
- <enumerator name="Key_Super_L" value="16777299"/>
- <enumerator name="Key_Super_R" value="16777300"/>
- <enumerator name="Key_Menu" value="16777301"/>
- <enumerator name="Key_Hyper_L" value="16777302"/>
- <enumerator name="Key_Hyper_R" value="16777303"/>
- <enumerator name="Key_Help" value="16777304"/>
- <enumerator name="Key_Direction_L" value="16777305"/>
- <enumerator name="Key_Direction_R" value="16777312"/>
- <enumerator name="Key_Space" value="32"/>
- <enumerator name="Key_Any" value="32"/>
- <enumerator name="Key_Exclam" value="33"/>
- <enumerator name="Key_QuoteDbl" value="34"/>
- <enumerator name="Key_NumberSign" value="35"/>
- <enumerator name="Key_Dollar" value="36"/>
- <enumerator name="Key_Percent" value="37"/>
- <enumerator name="Key_Ampersand" value="38"/>
- <enumerator name="Key_Apostrophe" value="39"/>
- <enumerator name="Key_ParenLeft" value="40"/>
- <enumerator name="Key_ParenRight" value="41"/>
- <enumerator name="Key_Asterisk" value="42"/>
- <enumerator name="Key_Plus" value="43"/>
- <enumerator name="Key_Comma" value="44"/>
- <enumerator name="Key_Minus" value="45"/>
- <enumerator name="Key_Period" value="46"/>
- <enumerator name="Key_Slash" value="47"/>
- <enumerator name="Key_0" value="48"/>
- <enumerator name="Key_1" value="49"/>
- <enumerator name="Key_2" value="50"/>
- <enumerator name="Key_3" value="51"/>
- <enumerator name="Key_4" value="52"/>
- <enumerator name="Key_5" value="53"/>
- <enumerator name="Key_6" value="54"/>
- <enumerator name="Key_7" value="55"/>
- <enumerator name="Key_8" value="56"/>
- <enumerator name="Key_9" value="57"/>
- <enumerator name="Key_Colon" value="58"/>
- <enumerator name="Key_Semicolon" value="59"/>
- <enumerator name="Key_Less" value="60"/>
- <enumerator name="Key_Equal" value="61"/>
- <enumerator name="Key_Greater" value="62"/>
- <enumerator name="Key_Question" value="63"/>
- <enumerator name="Key_At" value="64"/>
- <enumerator name="Key_A" value="65"/>
- <enumerator name="Key_B" value="66"/>
- <enumerator name="Key_C" value="67"/>
- <enumerator name="Key_D" value="68"/>
- <enumerator name="Key_E" value="69"/>
- <enumerator name="Key_F" value="70"/>
- <enumerator name="Key_G" value="71"/>
- <enumerator name="Key_H" value="72"/>
- <enumerator name="Key_I" value="73"/>
- <enumerator name="Key_J" value="74"/>
- <enumerator name="Key_K" value="75"/>
- <enumerator name="Key_L" value="76"/>
- <enumerator name="Key_M" value="77"/>
- <enumerator name="Key_N" value="78"/>
- <enumerator name="Key_O" value="79"/>
- <enumerator name="Key_P" value="80"/>
- <enumerator name="Key_Q" value="81"/>
- <enumerator name="Key_R" value="82"/>
- <enumerator name="Key_S" value="83"/>
- <enumerator name="Key_T" value="84"/>
- <enumerator name="Key_U" value="85"/>
- <enumerator name="Key_V" value="86"/>
- <enumerator name="Key_W" value="87"/>
- <enumerator name="Key_X" value="88"/>
- <enumerator name="Key_Y" value="89"/>
- <enumerator name="Key_Z" value="90"/>
- <enumerator name="Key_BracketLeft" value="91"/>
- <enumerator name="Key_Backslash" value="92"/>
- <enumerator name="Key_BracketRight" value="93"/>
- <enumerator name="Key_AsciiCircum" value="94"/>
- <enumerator name="Key_Underscore" value="95"/>
- <enumerator name="Key_QuoteLeft" value="96"/>
- <enumerator name="Key_BraceLeft" value="123"/>
- <enumerator name="Key_Bar" value="124"/>
- <enumerator name="Key_BraceRight" value="125"/>
- <enumerator name="Key_AsciiTilde" value="126"/>
- <enumerator name="Key_nobreakspace" value="160"/>
- <enumerator name="Key_exclamdown" value="161"/>
- <enumerator name="Key_cent" value="162"/>
- <enumerator name="Key_sterling" value="163"/>
- <enumerator name="Key_currency" value="164"/>
- <enumerator name="Key_yen" value="165"/>
- <enumerator name="Key_brokenbar" value="166"/>
- <enumerator name="Key_section" value="167"/>
- <enumerator name="Key_diaeresis" value="168"/>
- <enumerator name="Key_copyright" value="169"/>
- <enumerator name="Key_ordfeminine" value="170"/>
- <enumerator name="Key_guillemotleft" value="171"/>
- <enumerator name="Key_notsign" value="172"/>
- <enumerator name="Key_hyphen" value="173"/>
- <enumerator name="Key_registered" value="174"/>
- <enumerator name="Key_macron" value="175"/>
- <enumerator name="Key_degree" value="176"/>
- <enumerator name="Key_plusminus" value="177"/>
- <enumerator name="Key_twosuperior" value="178"/>
- <enumerator name="Key_threesuperior" value="179"/>
- <enumerator name="Key_acute" value="180"/>
- <enumerator name="Key_mu" value="181"/>
- <enumerator name="Key_paragraph" value="182"/>
- <enumerator name="Key_periodcentered" value="183"/>
- <enumerator name="Key_cedilla" value="184"/>
- <enumerator name="Key_onesuperior" value="185"/>
- <enumerator name="Key_masculine" value="186"/>
- <enumerator name="Key_guillemotright" value="187"/>
- <enumerator name="Key_onequarter" value="188"/>
- <enumerator name="Key_onehalf" value="189"/>
- <enumerator name="Key_threequarters" value="190"/>
- <enumerator name="Key_questiondown" value="191"/>
- <enumerator name="Key_Agrave" value="192"/>
- <enumerator name="Key_Aacute" value="193"/>
- <enumerator name="Key_Acircumflex" value="194"/>
- <enumerator name="Key_Atilde" value="195"/>
- <enumerator name="Key_Adiaeresis" value="196"/>
- <enumerator name="Key_Aring" value="197"/>
- <enumerator name="Key_AE" value="198"/>
- <enumerator name="Key_Ccedilla" value="199"/>
- <enumerator name="Key_Egrave" value="200"/>
- <enumerator name="Key_Eacute" value="201"/>
- <enumerator name="Key_Ecircumflex" value="202"/>
- <enumerator name="Key_Ediaeresis" value="203"/>
- <enumerator name="Key_Igrave" value="204"/>
- <enumerator name="Key_Iacute" value="205"/>
- <enumerator name="Key_Icircumflex" value="206"/>
- <enumerator name="Key_Idiaeresis" value="207"/>
- <enumerator name="Key_ETH" value="208"/>
- <enumerator name="Key_Ntilde" value="209"/>
- <enumerator name="Key_Ograve" value="210"/>
- <enumerator name="Key_Oacute" value="211"/>
- <enumerator name="Key_Ocircumflex" value="212"/>
- <enumerator name="Key_Otilde" value="213"/>
- <enumerator name="Key_Odiaeresis" value="214"/>
- <enumerator name="Key_multiply" value="215"/>
- <enumerator name="Key_Ooblique" value="216"/>
- <enumerator name="Key_Ugrave" value="217"/>
- <enumerator name="Key_Uacute" value="218"/>
- <enumerator name="Key_Ucircumflex" value="219"/>
- <enumerator name="Key_Udiaeresis" value="220"/>
- <enumerator name="Key_Yacute" value="221"/>
- <enumerator name="Key_THORN" value="222"/>
- <enumerator name="Key_ssharp" value="223"/>
- <enumerator name="Key_division" value="247"/>
- <enumerator name="Key_ydiaeresis" value="255"/>
- <enumerator name="Key_AltGr" value="16781571"/>
- <enumerator name="Key_Multi_key" value="16781600"/>
- <enumerator name="Key_Codeinput" value="16781623"/>
- <enumerator name="Key_SingleCandidate" value="16781628"/>
- <enumerator name="Key_MultipleCandidate" value="16781629"/>
- <enumerator name="Key_PreviousCandidate" value="16781630"/>
- <enumerator name="Key_Mode_switch" value="16781694"/>
- <enumerator name="Key_Kanji" value="16781601"/>
- <enumerator name="Key_Muhenkan" value="16781602"/>
- <enumerator name="Key_Henkan" value="16781603"/>
- <enumerator name="Key_Romaji" value="16781604"/>
- <enumerator name="Key_Hiragana" value="16781605"/>
- <enumerator name="Key_Katakana" value="16781606"/>
- <enumerator name="Key_Hiragana_Katakana" value="16781607"/>
- <enumerator name="Key_Zenkaku" value="16781608"/>
- <enumerator name="Key_Hankaku" value="16781609"/>
- <enumerator name="Key_Zenkaku_Hankaku" value="16781610"/>
- <enumerator name="Key_Touroku" value="16781611"/>
- <enumerator name="Key_Massyo" value="16781612"/>
- <enumerator name="Key_Kana_Lock" value="16781613"/>
- <enumerator name="Key_Kana_Shift" value="16781614"/>
- <enumerator name="Key_Eisu_Shift" value="16781615"/>
- <enumerator name="Key_Eisu_toggle" value="16781616"/>
- <enumerator name="Key_Hangul" value="16781617"/>
- <enumerator name="Key_Hangul_Start" value="16781618"/>
- <enumerator name="Key_Hangul_End" value="16781619"/>
- <enumerator name="Key_Hangul_Hanja" value="16781620"/>
- <enumerator name="Key_Hangul_Jamo" value="16781621"/>
- <enumerator name="Key_Hangul_Romaja" value="16781622"/>
- <enumerator name="Key_Hangul_Jeonja" value="16781624"/>
- <enumerator name="Key_Hangul_Banja" value="16781625"/>
- <enumerator name="Key_Hangul_PreHanja" value="16781626"/>
- <enumerator name="Key_Hangul_PostHanja" value="16781627"/>
- <enumerator name="Key_Hangul_Special" value="16781631"/>
- <enumerator name="Key_Dead_Grave" value="16781904"/>
- <enumerator name="Key_Dead_Acute" value="16781905"/>
- <enumerator name="Key_Dead_Circumflex" value="16781906"/>
- <enumerator name="Key_Dead_Tilde" value="16781907"/>
- <enumerator name="Key_Dead_Macron" value="16781908"/>
- <enumerator name="Key_Dead_Breve" value="16781909"/>
- <enumerator name="Key_Dead_Abovedot" value="16781910"/>
- <enumerator name="Key_Dead_Diaeresis" value="16781911"/>
- <enumerator name="Key_Dead_Abovering" value="16781912"/>
- <enumerator name="Key_Dead_Doubleacute" value="16781913"/>
- <enumerator name="Key_Dead_Caron" value="16781914"/>
- <enumerator name="Key_Dead_Cedilla" value="16781915"/>
- <enumerator name="Key_Dead_Ogonek" value="16781916"/>
- <enumerator name="Key_Dead_Iota" value="16781917"/>
- <enumerator name="Key_Dead_Voiced_Sound" value="16781918"/>
- <enumerator name="Key_Dead_Semivoiced_Sound" value="16781919"/>
- <enumerator name="Key_Dead_Belowdot" value="16781920"/>
- <enumerator name="Key_Dead_Hook" value="16781921"/>
- <enumerator name="Key_Dead_Horn" value="16781922"/>
- <enumerator name="Key_Back" value="16777313"/>
- <enumerator name="Key_Forward" value="16777314"/>
- <enumerator name="Key_Stop" value="16777315"/>
- <enumerator name="Key_Refresh" value="16777316"/>
- <enumerator name="Key_VolumeDown" value="16777328"/>
- <enumerator name="Key_VolumeMute" value="16777329"/>
- <enumerator name="Key_VolumeUp" value="16777330"/>
- <enumerator name="Key_BassBoost" value="16777331"/>
- <enumerator name="Key_BassUp" value="16777332"/>
- <enumerator name="Key_BassDown" value="16777333"/>
- <enumerator name="Key_TrebleUp" value="16777334"/>
- <enumerator name="Key_TrebleDown" value="16777335"/>
- <enumerator name="Key_MediaPlay" value="16777344"/>
- <enumerator name="Key_MediaStop" value="16777345"/>
- <enumerator name="Key_MediaPrevious" value="16777346"/>
- <enumerator name="Key_MediaNext" value="16777347"/>
- <enumerator name="Key_MediaRecord" value="16777348"/>
- <enumerator name="Key_HomePage" value="16777360"/>
- <enumerator name="Key_Favorites" value="16777361"/>
- <enumerator name="Key_Search" value="16777362"/>
- <enumerator name="Key_Standby" value="16777363"/>
- <enumerator name="Key_OpenUrl" value="16777364"/>
- <enumerator name="Key_LaunchMail" value="16777376"/>
- <enumerator name="Key_LaunchMedia" value="16777377"/>
- <enumerator name="Key_Launch0" value="16777378"/>
- <enumerator name="Key_Launch1" value="16777379"/>
- <enumerator name="Key_Launch2" value="16777380"/>
- <enumerator name="Key_Launch3" value="16777381"/>
- <enumerator name="Key_Launch4" value="16777382"/>
- <enumerator name="Key_Launch5" value="16777383"/>
- <enumerator name="Key_Launch6" value="16777384"/>
- <enumerator name="Key_Launch7" value="16777385"/>
- <enumerator name="Key_Launch8" value="16777386"/>
- <enumerator name="Key_Launch9" value="16777387"/>
- <enumerator name="Key_LaunchA" value="16777388"/>
- <enumerator name="Key_LaunchB" value="16777389"/>
- <enumerator name="Key_LaunchC" value="16777390"/>
- <enumerator name="Key_LaunchD" value="16777391"/>
- <enumerator name="Key_LaunchE" value="16777392"/>
- <enumerator name="Key_LaunchF" value="16777393"/>
- <enumerator name="Key_MonBrightnessUp" value="16777394"/>
- <enumerator name="Key_MonBrightnessDown" value="16777395"/>
- <enumerator name="Key_KeyboardLightOnOff" value="16777396"/>
- <enumerator name="Key_KeyboardBrightnessUp" value="16777397"/>
- <enumerator name="Key_KeyboardBrightnessDown" value="16777398"/>
- <enumerator name="Key_PowerOff" value="16777399"/>
- <enumerator name="Key_WakeUp" value="16777400"/>
- <enumerator name="Key_Eject" value="16777401"/>
- <enumerator name="Key_ScreenSaver" value="16777402"/>
- <enumerator name="Key_WWW" value="16777403"/>
- <enumerator name="Key_Memo" value="16777404"/>
- <enumerator name="Key_LightBulb" value="16777405"/>
- <enumerator name="Key_Shop" value="16777406"/>
- <enumerator name="Key_History" value="16777407"/>
- <enumerator name="Key_AddFavorite" value="16777408"/>
- <enumerator name="Key_HotLinks" value="16777409"/>
- <enumerator name="Key_BrightnessAdjust" value="16777410"/>
- <enumerator name="Key_Finance" value="16777411"/>
- <enumerator name="Key_Community" value="16777412"/>
- <enumerator name="Key_AudioRewind" value="16777413"/>
- <enumerator name="Key_BackForward" value="16777414"/>
- <enumerator name="Key_ApplicationLeft" value="16777415"/>
- <enumerator name="Key_ApplicationRight" value="16777416"/>
- <enumerator name="Key_Book" value="16777417"/>
- <enumerator name="Key_CD" value="16777418"/>
- <enumerator name="Key_Calculator" value="16777419"/>
- <enumerator name="Key_ToDoList" value="16777420"/>
- <enumerator name="Key_ClearGrab" value="16777421"/>
- <enumerator name="Key_Close" value="16777422"/>
- <enumerator name="Key_Copy" value="16777423"/>
- <enumerator name="Key_Cut" value="16777424"/>
- <enumerator name="Key_Display" value="16777425"/>
- <enumerator name="Key_DOS" value="16777426"/>
- <enumerator name="Key_Documents" value="16777427"/>
- <enumerator name="Key_Excel" value="16777428"/>
- <enumerator name="Key_Explorer" value="16777429"/>
- <enumerator name="Key_Game" value="16777430"/>
- <enumerator name="Key_Go" value="16777431"/>
- <enumerator name="Key_iTouch" value="16777432"/>
- <enumerator name="Key_LogOff" value="16777433"/>
- <enumerator name="Key_Market" value="16777434"/>
- <enumerator name="Key_Meeting" value="16777435"/>
- <enumerator name="Key_MenuKB" value="16777436"/>
- <enumerator name="Key_MenuPB" value="16777437"/>
- <enumerator name="Key_MySites" value="16777438"/>
- <enumerator name="Key_News" value="16777439"/>
- <enumerator name="Key_OfficeHome" value="16777440"/>
- <enumerator name="Key_Option" value="16777441"/>
- <enumerator name="Key_Paste" value="16777442"/>
- <enumerator name="Key_Phone" value="16777443"/>
- <enumerator name="Key_Calendar" value="16777444"/>
- <enumerator name="Key_Reply" value="16777445"/>
- <enumerator name="Key_Reload" value="16777446"/>
- <enumerator name="Key_RotateWindows" value="16777447"/>
- <enumerator name="Key_RotationPB" value="16777448"/>
- <enumerator name="Key_RotationKB" value="16777449"/>
- <enumerator name="Key_Save" value="16777450"/>
- <enumerator name="Key_Send" value="16777451"/>
- <enumerator name="Key_Spell" value="16777452"/>
- <enumerator name="Key_SplitScreen" value="16777453"/>
- <enumerator name="Key_Support" value="16777454"/>
- <enumerator name="Key_TaskPane" value="16777455"/>
- <enumerator name="Key_Terminal" value="16777456"/>
- <enumerator name="Key_Tools" value="16777457"/>
- <enumerator name="Key_Travel" value="16777458"/>
- <enumerator name="Key_Video" value="16777459"/>
- <enumerator name="Key_Word" value="16777460"/>
- <enumerator name="Key_Xfer" value="16777461"/>
- <enumerator name="Key_ZoomIn" value="16777462"/>
- <enumerator name="Key_ZoomOut" value="16777463"/>
- <enumerator name="Key_Away" value="16777464"/>
- <enumerator name="Key_Messenger" value="16777465"/>
- <enumerator name="Key_WebCam" value="16777466"/>
- <enumerator name="Key_MailForward" value="16777467"/>
- <enumerator name="Key_Pictures" value="16777468"/>
- <enumerator name="Key_Music" value="16777469"/>
- <enumerator name="Key_Battery" value="16777470"/>
- <enumerator name="Key_Bluetooth" value="16777471"/>
- <enumerator name="Key_WLAN" value="16777472"/>
- <enumerator name="Key_UWB" value="16777473"/>
- <enumerator name="Key_AudioForward" value="16777474"/>
- <enumerator name="Key_AudioRepeat" value="16777475"/>
- <enumerator name="Key_AudioRandomPlay" value="16777476"/>
- <enumerator name="Key_Subtitle" value="16777477"/>
- <enumerator name="Key_AudioCycleTrack" value="16777478"/>
- <enumerator name="Key_Time" value="16777479"/>
- <enumerator name="Key_Hibernate" value="16777480"/>
- <enumerator name="Key_View" value="16777481"/>
- <enumerator name="Key_TopMenu" value="16777482"/>
- <enumerator name="Key_PowerDown" value="16777483"/>
- <enumerator name="Key_Suspend" value="16777484"/>
- <enumerator name="Key_ContrastAdjust" value="16777485"/>
- <enumerator name="Key_LaunchG" value="16777486"/>
- <enumerator name="Key_LaunchH" value="16777487"/>
- <enumerator name="Key_MediaLast" value="16842751"/>
- <enumerator name="Key_Select" value="16842752"/>
- <enumerator name="Key_Yes" value="16842753"/>
- <enumerator name="Key_No" value="16842754"/>
- <enumerator name="Key_Cancel" value="16908289"/>
- <enumerator name="Key_Printer" value="16908290"/>
- <enumerator name="Key_Execute" value="16908291"/>
- <enumerator name="Key_Sleep" value="16908292"/>
- <enumerator name="Key_Play" value="16908293"/>
- <enumerator name="Key_Zoom" value="16908294"/>
- <enumerator name="Key_Context1" value="17825792"/>
- <enumerator name="Key_Context2" value="17825793"/>
- <enumerator name="Key_Context3" value="17825794"/>
- <enumerator name="Key_Context4" value="17825795"/>
- <enumerator name="Key_Call" value="17825796"/>
- <enumerator name="Key_Hangup" value="17825797"/>
- <enumerator name="Key_Flip" value="17825798"/>
- <enumerator name="Key_Camera" value="17825799"/>
- <enumerator name="Key_CameraFocus" value="17825800"/>
- <enumerator name="Key_unknown" value="33554431"/>
- </enum>
- <enum name="ArrowType">
- <enumerator name="NoArrow" value="0"/>
- <enumerator name="UpArrow" value="1"/>
- <enumerator name="DownArrow" value="2"/>
- <enumerator name="LeftArrow" value="3"/>
- <enumerator name="RightArrow" value="4"/>
- </enum>
- <enum name="PenStyle">
- <enumerator name="NoPen" value="0"/>
- <enumerator name="SolidLine" value="1"/>
- <enumerator name="DashLine" value="2"/>
- <enumerator name="DotLine" value="3"/>
- <enumerator name="DashDotLine" value="4"/>
- <enumerator name="DashDotDotLine" value="5"/>
- <enumerator name="CustomDashLine" value="6"/>
- </enum>
- <enum name="PenCapStyle">
- <enumerator name="FlatCap" value="0"/>
- <enumerator name="SquareCap" value="16"/>
- <enumerator name="RoundCap" value="32"/>
- <enumerator name="MPenCapStyle" value="48"/>
- </enum>
- <enum name="PenJoinStyle">
- <enumerator name="MiterJoin" value="0"/>
- <enumerator name="BevelJoin" value="64"/>
- <enumerator name="RoundJoin" value="128"/>
- <enumerator name="SvgMiterJoin" value="256"/>
- <enumerator name="MPenJoinStyle" value="448"/>
- </enum>
- <enum name="BrushStyle">
- <enumerator name="NoBrush" value="0"/>
- <enumerator name="SolidPattern" value="1"/>
- <enumerator name="Dense1Pattern" value="2"/>
- <enumerator name="Dense2Pattern" value="3"/>
- <enumerator name="Dense3Pattern" value="4"/>
- <enumerator name="Dense4Pattern" value="5"/>
- <enumerator name="Dense5Pattern" value="6"/>
- <enumerator name="Dense6Pattern" value="7"/>
- <enumerator name="Dense7Pattern" value="8"/>
- <enumerator name="HorPattern" value="9"/>
- <enumerator name="VerPattern" value="10"/>
- <enumerator name="CrossPattern" value="11"/>
- <enumerator name="BDiagPattern" value="12"/>
- <enumerator name="FDiagPattern" value="13"/>
- <enumerator name="DiagCrossPattern" value="14"/>
- <enumerator name="LinearGradientPattern" value="15"/>
- <enumerator name="RadialGradientPattern" value="16"/>
- <enumerator name="ConicalGradientPattern" value="17"/>
- <enumerator name="TexturePattern" value="24"/>
- </enum>
- <enum name="SizeMode">
- <enumerator name="AbsoluteSize" value="0"/>
- <enumerator name="RelativeSize" value="1"/>
- </enum>
- <enum name="CursorShape">
- <enumerator name="ArrowCursor" value="0"/>
- <enumerator name="UpArrowCursor" value="1"/>
- <enumerator name="CrossCursor" value="2"/>
- <enumerator name="WaitCursor" value="3"/>
- <enumerator name="IBeamCursor" value="4"/>
- <enumerator name="SizeVerCursor" value="5"/>
- <enumerator name="SizeHorCursor" value="6"/>
- <enumerator name="SizeBDiagCursor" value="7"/>
- <enumerator name="SizeFDiagCursor" value="8"/>
- <enumerator name="SizeAllCursor" value="9"/>
- <enumerator name="BlankCursor" value="10"/>
- <enumerator name="SplitVCursor" value="11"/>
- <enumerator name="SplitHCursor" value="12"/>
- <enumerator name="PointingHandCursor" value="13"/>
- <enumerator name="ForbiddenCursor" value="14"/>
- <enumerator name="WhatsThisCursor" value="15"/>
- <enumerator name="BusyCursor" value="16"/>
- <enumerator name="OpenHandCursor" value="17"/>
- <enumerator name="ClosedHandCursor" value="18"/>
- <enumerator name="DragCopyCursor" value="19"/>
- <enumerator name="DragMoveCursor" value="20"/>
- <enumerator name="DragLinkCursor" value="21"/>
- <enumerator name="LastCursor" value="21"/>
- <enumerator name="BitmapCursor" value="24"/>
- <enumerator name="CustomCursor" value="25"/>
- </enum>
- <enum name="TextFormat">
- <enumerator name="PlainText" value="0"/>
- <enumerator name="RichText" value="1"/>
- <enumerator name="AutoText" value="2"/>
- <enumerator name="LogText" value="3"/>
- </enum>
- <enum name="AspectRatioMode">
- <enumerator name="IgnoreAspectRatio" value="0"/>
- <enumerator name="KeepAspectRatio" value="1"/>
- <enumerator name="KeepAspectRatioByExpanding" value="2"/>
- </enum>
- <enum name="DockWidgetArea">
- <enumerator name="LeftDockWidgetArea" value="1"/>
- <enumerator name="RightDockWidgetArea" value="2"/>
- <enumerator name="TopDockWidgetArea" value="4"/>
- <enumerator name="BottomDockWidgetArea" value="8"/>
- <enumerator name="DockWidgetArea_Mask" value="15"/>
- <enumerator name="AllDockWidgetAreas" value="15"/>
- <enumerator name="NoDockWidgetArea" value="0"/>
- </enum>
- <enum name="DockWidgetAreas">
- <enumerator name="LeftDockWidgetArea" value="1"/>
- <enumerator name="RightDockWidgetArea" value="2"/>
- <enumerator name="TopDockWidgetArea" value="4"/>
- <enumerator name="BottomDockWidgetArea" value="8"/>
- <enumerator name="DockWidgetArea_Mask" value="15"/>
- <enumerator name="AllDockWidgetAreas" value="15"/>
- <enumerator name="NoDockWidgetArea" value="0"/>
- </enum>
- <enum name="ToolBarArea">
- <enumerator name="LeftToolBarArea" value="1"/>
- <enumerator name="RightToolBarArea" value="2"/>
- <enumerator name="TopToolBarArea" value="4"/>
- <enumerator name="BottomToolBarArea" value="8"/>
- <enumerator name="ToolBarArea_Mask" value="15"/>
- <enumerator name="AllToolBarAreas" value="15"/>
- <enumerator name="NoToolBarArea" value="0"/>
- </enum>
- <enum name="ToolBarAreas">
- <enumerator name="LeftToolBarArea" value="1"/>
- <enumerator name="RightToolBarArea" value="2"/>
- <enumerator name="TopToolBarArea" value="4"/>
- <enumerator name="BottomToolBarArea" value="8"/>
- <enumerator name="ToolBarArea_Mask" value="15"/>
- <enumerator name="AllToolBarAreas" value="15"/>
- <enumerator name="NoToolBarArea" value="0"/>
- </enum>
- <enum name="DateFormat">
- <enumerator name="TextDate" value="0"/>
- <enumerator name="ISODate" value="1"/>
- <enumerator name="SystemLocaleDate" value="2"/>
- <enumerator name="LocalDate" value="2"/>
- <enumerator name="LocaleDate" value="3"/>
- <enumerator name="SystemLocaleShortDate" value="4"/>
- <enumerator name="SystemLocaleLongDate" value="5"/>
- <enumerator name="DefaultLocaleShortDate" value="6"/>
- <enumerator name="DefaultLocaleLongDate" value="7"/>
- </enum>
- <enum name="TimeSpec">
- <enumerator name="LocalTime" value="0"/>
- <enumerator name="UTC" value="1"/>
- <enumerator name="OffsetFromUTC" value="2"/>
- </enum>
- <enum name="DayOfWeek">
- <enumerator name="Monday" value="1"/>
- <enumerator name="Tuesday" value="2"/>
- <enumerator name="Wednesday" value="3"/>
- <enumerator name="Thursday" value="4"/>
- <enumerator name="Friday" value="5"/>
- <enumerator name="Saturday" value="6"/>
- <enumerator name="Sunday" value="7"/>
- </enum>
- <enum name="ScrollBarPolicy">
- <enumerator name="ScrollBarAsNeeded" value="0"/>
- <enumerator name="ScrollBarAlwaysOff" value="1"/>
- <enumerator name="ScrollBarAlwaysOn" value="2"/>
- </enum>
- <enum name="CaseSensitivity">
- <enumerator name="CaseInsensitive" value="0"/>
- <enumerator name="CaseSensitive" value="1"/>
- </enum>
- <enum name="Corner">
- <enumerator name="TopLeftCorner" value="0"/>
- <enumerator name="TopRightCorner" value="1"/>
- <enumerator name="BottomLeftCorner" value="2"/>
- <enumerator name="BottomRightCorner" value="3"/>
- </enum>
- <enum name="ConnectionType">
- <enumerator name="AutoConnection" value="0"/>
- <enumerator name="DirectConnection" value="1"/>
- <enumerator name="QueuedConnection" value="2"/>
- <enumerator name="AutoCompatConnection" value="3"/>
- <enumerator name="BlockingQueuedConnection" value="4"/>
- <enumerator name="UniqueConnection" value="128"/>
- </enum>
- <enum name="ShortcutContext">
- <enumerator name="WidgetShortcut" value="0"/>
- <enumerator name="WindowShortcut" value="1"/>
- <enumerator name="ApplicationShortcut" value="2"/>
- <enumerator name="WidgetWithChildrenShortcut" value="3"/>
- </enum>
- <enum name="FillRule">
- <enumerator name="OddEvenFill" value="0"/>
- <enumerator name="WindingFill" value="1"/>
- </enum>
- <enum name="MaskMode">
- <enumerator name="MaskInColor" value="0"/>
- <enumerator name="MaskOutColor" value="1"/>
- </enum>
- <enum name="ClipOperation">
- <enumerator name="NoClip" value="0"/>
- <enumerator name="ReplaceClip" value="1"/>
- <enumerator name="IntersectClip" value="2"/>
- <enumerator name="UniteClip" value="3"/>
- </enum>
- <enum name="ItemSelectionMode">
- <enumerator name="ContainsItemShape" value="0"/>
- <enumerator name="IntersectsItemShape" value="1"/>
- <enumerator name="ContainsItemBoundingRect" value="2"/>
- <enumerator name="IntersectsItemBoundingRect" value="3"/>
- </enum>
- <enum name="TransformationMode">
- <enumerator name="FastTransformation" value="0"/>
- <enumerator name="SmoothTransformation" value="1"/>
- </enum>
- <enum name="Axis">
- <enumerator name="XAxis" value="0"/>
- <enumerator name="YAxis" value="1"/>
- <enumerator name="ZAxis" value="2"/>
- </enum>
- <enum name="ContextMenuPolicy">
- <enumerator name="NoContextMenu" value="0"/>
- <enumerator name="DefaultContextMenu" value="1"/>
- <enumerator name="ActionsContextMenu" value="2"/>
- <enumerator name="CustomContextMenu" value="3"/>
- <enumerator name="PreventContextMenu" value="4"/>
- </enum>
- <enum name="InputMethodHint">
- <enumerator name="ImhNone" value="0"/>
- <enumerator name="ImhHiddenText" value="1"/>
- <enumerator name="ImhNoAutoUppercase" value="2"/>
- <enumerator name="ImhPreferNumbers" value="4"/>
- <enumerator name="ImhPreferUppercase" value="8"/>
- <enumerator name="ImhPreferLowercase" value="16"/>
- <enumerator name="ImhNoPredictiveText" value="32"/>
- <enumerator name="ImhDigitsOnly" value="65536"/>
- <enumerator name="ImhFormattedNumbersOnly" value="131072"/>
- <enumerator name="ImhUppercaseOnly" value="262144"/>
- <enumerator name="ImhLowercaseOnly" value="524288"/>
- <enumerator name="ImhDialableCharactersOnly" value="1048576"/>
- <enumerator name="ImhEmailCharactersOnly" value="2097152"/>
- <enumerator name="ImhUrlCharactersOnly" value="4194304"/>
- <enumerator name="ImhExclusiveInputMask" value="-65536"/>
- </enum>
- <enum name="InputMethodHints">
- <enumerator name="ImhNone" value="0"/>
- <enumerator name="ImhHiddenText" value="1"/>
- <enumerator name="ImhNoAutoUppercase" value="2"/>
- <enumerator name="ImhPreferNumbers" value="4"/>
- <enumerator name="ImhPreferUppercase" value="8"/>
- <enumerator name="ImhPreferLowercase" value="16"/>
- <enumerator name="ImhNoPredictiveText" value="32"/>
- <enumerator name="ImhDigitsOnly" value="65536"/>
- <enumerator name="ImhFormattedNumbersOnly" value="131072"/>
- <enumerator name="ImhUppercaseOnly" value="262144"/>
- <enumerator name="ImhLowercaseOnly" value="524288"/>
- <enumerator name="ImhDialableCharactersOnly" value="1048576"/>
- <enumerator name="ImhEmailCharactersOnly" value="2097152"/>
- <enumerator name="ImhUrlCharactersOnly" value="4194304"/>
- <enumerator name="ImhExclusiveInputMask" value="-65536"/>
- </enum>
- <enum name="ToolButtonStyle">
- <enumerator name="ToolButtonIconOnly" value="0"/>
- <enumerator name="ToolButtonTextOnly" value="1"/>
- <enumerator name="ToolButtonTextBesideIcon" value="2"/>
- <enumerator name="ToolButtonTextUnderIcon" value="3"/>
- <enumerator name="ToolButtonFollowStyle" value="4"/>
- </enum>
- <enum name="LayoutDirection">
- <enumerator name="LeftToRight" value="0"/>
- <enumerator name="RightToLeft" value="1"/>
- </enum>
- <enum name="DropAction">
- <enumerator name="CopyAction" value="1"/>
- <enumerator name="MoveAction" value="2"/>
- <enumerator name="LinkAction" value="4"/>
- <enumerator name="ActionMask" value="255"/>
- <enumerator name="TargetMoveAction" value="32770"/>
- <enumerator name="IgnoreAction" value="0"/>
- </enum>
- <enum name="DropActions">
- <enumerator name="CopyAction" value="1"/>
- <enumerator name="MoveAction" value="2"/>
- <enumerator name="LinkAction" value="4"/>
- <enumerator name="ActionMask" value="255"/>
- <enumerator name="TargetMoveAction" value="32770"/>
- <enumerator name="IgnoreAction" value="0"/>
- </enum>
- <enum name="CheckState">
- <enumerator name="Unchecked" value="0"/>
- <enumerator name="PartiallyChecked" value="1"/>
- <enumerator name="Checked" value="2"/>
- </enum>
- <enum name="ItemFlags">
- <enumerator name="NoItemFlags" value="0"/>
- <enumerator name="ItemIsSelectable" value="1"/>
- <enumerator name="ItemIsEditable" value="2"/>
- <enumerator name="ItemIsDragEnabled" value="4"/>
- <enumerator name="ItemIsDropEnabled" value="8"/>
- <enumerator name="ItemIsUserCheckable" value="16"/>
- <enumerator name="ItemIsEnabled" value="32"/>
- <enumerator name="ItemIsTristate" value="64"/>
- </enum>
- <enum name="MatchFlags">
- <enumerator name="MatchExactly" value="0"/>
- <enumerator name="MatchContains" value="1"/>
- <enumerator name="MatchStartsWith" value="2"/>
- <enumerator name="MatchEndsWith" value="3"/>
- <enumerator name="MatchRegExp" value="4"/>
- <enumerator name="MatchWildcard" value="5"/>
- <enumerator name="MatchFixedString" value="8"/>
- <enumerator name="MatchCaseSensitive" value="16"/>
- <enumerator name="MatchWrap" value="32"/>
- <enumerator name="MatchRecursive" value="64"/>
- </enum>
- <enum name="WindowModality">
- <enumerator name="NonModal" value="0"/>
- <enumerator name="WindowModal" value="1"/>
- <enumerator name="ApplicationModal" value="2"/>
- </enum>
- <enum name="TextInteractionFlag">
- <enumerator name="NoTextInteraction" value="0"/>
- <enumerator name="TextSelectableByMouse" value="1"/>
- <enumerator name="TextSelectableByKeyboard" value="2"/>
- <enumerator name="LinksAccessibleByMouse" value="4"/>
- <enumerator name="LinksAccessibleByKeyboard" value="8"/>
- <enumerator name="TextEditable" value="16"/>
- <enumerator name="TextEditorInteraction" value="19"/>
- <enumerator name="TextBrowserInteraction" value="13"/>
- </enum>
- <enum name="TextInteractionFlags">
- <enumerator name="NoTextInteraction" value="0"/>
- <enumerator name="TextSelectableByMouse" value="1"/>
- <enumerator name="TextSelectableByKeyboard" value="2"/>
- <enumerator name="LinksAccessibleByMouse" value="4"/>
- <enumerator name="LinksAccessibleByKeyboard" value="8"/>
- <enumerator name="TextEditable" value="16"/>
- <enumerator name="TextEditorInteraction" value="19"/>
- <enumerator name="TextBrowserInteraction" value="13"/>
- </enum>
- <enum name="SizeHint">
- <enumerator name="MinimumSize" value="0"/>
- <enumerator name="PreferredSize" value="1"/>
- <enumerator name="MaximumSize" value="2"/>
- <enumerator name="MinimumDescent" value="3"/>
- <enumerator name="NSizeHints" value="4"/>
- </enum>
- </type>
- <type name="Qt.AnchorAnimation" version="4.7" extends="Qt.Animation">
- <property name="targets" type="Qt.Item" isList="true"/>
- <property name="duration" type="int"/>
- <property name="easing" type="Qt.Easing"/>
- <signal name="durationChanged">
- <param type="int"/>
- </signal>
- <signal name="easingChanged">
- <param type="Qt.Easing"/>
- </signal>
- </type>
- <type name="Qt.AnchorChanges" version="4.7" extends="QDeclarativeStateOperation">
- <property name="target" type="Qt.Item"/>
- <property name="anchors" type="QDeclarativeAnchorSet"/>
- </type>
- <type name="Qt.AnimatedImage" version="4.7" defaultProperty="data" extends="Qt.Image">
- <property name="playing" type="bool"/>
- <property name="paused" type="bool"/>
- <property name="currentFrame" type="int"/>
- <property name="frameCount" type="int"/>
- <property name="sourceSize" type="QSize"/>
- <signal name="playingChanged"/>
- <signal name="pausedChanged"/>
- <signal name="frameChanged"/>
- <signal name="sourceSizeChanged"/>
- </type>
- <type name="Qt.Animation" version="4.7" extends="Qt.QtObject">
- <enum name="Loops">
- <enumerator name="Infinite" value="-2"/>
- </enum>
- <property name="running" type="bool"/>
- <property name="paused" type="bool"/>
- <property name="alwaysRunToEnd" type="bool"/>
- <property name="loops" type="int"/>
- <signal name="started"/>
- <signal name="completed"/>
- <signal name="runningChanged">
- <param type="bool"/>
- </signal>
- <signal name="pausedChanged">
- <param type="bool"/>
- </signal>
- <signal name="alwaysRunToEndChanged">
- <param type="bool"/>
- </signal>
- <signal name="loopCountChanged">
- <param type="int"/>
- </signal>
- <method name="restart"/>
- <method name="start"/>
- <method name="pause"/>
- <method name="resume"/>
- <method name="stop"/>
- <method name="complete"/>
- </type>
- <type name="Qt.Behavior" version="4.7" defaultProperty="animation" extends="Qt.QtObject">
- <property name="animation" type="Qt.Animation"/>
- <property name="enabled" type="bool"/>
- <signal name="enabledChanged"/>
- </type>
- <type name="Qt.Binding" version="4.7" extends="Qt.QtObject">
- <property name="target" type="Qt.QtObject"/>
- <property name="property" type="string"/>
- <property name="value" type="QVariant"/>
- <property name="when" type="bool"/>
- </type>
- <type name="Qt.BorderImage" version="4.7" defaultProperty="data" extends="QDeclarativeImageBase">
- <enum name="TileMode">
- <enumerator name="Stretch" value="0"/>
- <enumerator name="Repeat" value="1"/>
- <enumerator name="Round" value="2"/>
- </enum>
- <property name="border" type="QDeclarativeScaleGrid"/>
- <property name="horizontalTileMode" type="TileMode"/>
- <property name="verticalTileMode" type="TileMode"/>
- <signal name="horizontalTileModeChanged"/>
- <signal name="verticalTileModeChanged"/>
- </type>
- <type name="Qt.ColorAnimation" version="4.7" extends="Qt.PropertyAnimation">
- <property name="from" type="QColor"/>
- <property name="to" type="QColor"/>
- </type>
- <type name="Qt.Column" version="4.7" defaultProperty="data" extends="QDeclarativeBasePositioner"/>
- <type name="Qt.Component" version="4.7" extends="Qt.QtObject">
- <enum name="Status">
- <enumerator name="Null" value="0"/>
- <enumerator name="Ready" value="1"/>
- <enumerator name="Loading" value="2"/>
- <enumerator name="Error" value="3"/>
- </enum>
- <property name="progress" type="qreal"/>
- <property name="status" type="Status"/>
- <property name="url" type="QUrl"/>
- <signal name="statusChanged">
- <param type="QDeclarativeComponent.Status"/>
- </signal>
- <signal name="progressChanged">
- <param type="qreal"/>
- </signal>
- <method name="errorString" type="string"/>
- </type>
- <type name="Qt.Connections" version="4.7" extends="Qt.QtObject">
- <property name="target" type="Qt.QtObject"/>
- <property name="ignoreUnknownSignals" type="bool"/>
- <signal name="targetChanged"/>
- </type>
- <type name="Qt.DoubleValidator" version="4.7" extends="QValidator">
- <enum name="Notation">
- <enumerator name="StandardNotation" value="0"/>
- <enumerator name="ScientificNotation" value="1"/>
- </enum>
- <property name="bottom" type="double"/>
- <property name="top" type="double"/>
- <property name="decimals" type="int"/>
- <property name="notation" type="Notation"/>
- </type>
- <type name="Qt.Drag" version="4.7" extends="Qt.QtObject">
- <enum name="Axis">
- <enumerator name="XAxis" value="1"/>
- <enumerator name="YAxis" value="2"/>
- <enumerator name="XandYAxis" value="3"/>
- </enum>
- <property name="target" type="QGraphicsObject"/>
- <property name="axis" type="Axis"/>
- <property name="minimumX" type="qreal"/>
- <property name="maximumX" type="qreal"/>
- <property name="minimumY" type="qreal"/>
- <property name="maximumY" type="qreal"/>
- <property name="active" type="bool"/>
- <signal name="targetChanged"/>
- <signal name="axisChanged"/>
- <signal name="minimumXChanged"/>
- <signal name="maximumXChanged"/>
- <signal name="minimumYChanged"/>
- <signal name="maximumYChanged"/>
- <signal name="activeChanged"/>
- </type>
- <type name="Qt.Easing" version="4.7" extends="QDeclarativeValueType">
- <enum name="Type">
- <enumerator name="Linear" value="0"/>
- <enumerator name="InQuad" value="1"/>
- <enumerator name="OutQuad" value="2"/>
- <enumerator name="InOutQuad" value="3"/>
- <enumerator name="OutInQuad" value="4"/>
- <enumerator name="InCubic" value="5"/>
- <enumerator name="OutCubic" value="6"/>
- <enumerator name="InOutCubic" value="7"/>
- <enumerator name="OutInCubic" value="8"/>
- <enumerator name="InQuart" value="9"/>
- <enumerator name="OutQuart" value="10"/>
- <enumerator name="InOutQuart" value="11"/>
- <enumerator name="OutInQuart" value="12"/>
- <enumerator name="InQuint" value="13"/>
- <enumerator name="OutQuint" value="14"/>
- <enumerator name="InOutQuint" value="15"/>
- <enumerator name="OutInQuint" value="16"/>
- <enumerator name="InSine" value="17"/>
- <enumerator name="OutSine" value="18"/>
- <enumerator name="InOutSine" value="19"/>
- <enumerator name="OutInSine" value="20"/>
- <enumerator name="InExpo" value="21"/>
- <enumerator name="OutExpo" value="22"/>
- <enumerator name="InOutExpo" value="23"/>
- <enumerator name="OutInExpo" value="24"/>
- <enumerator name="InCirc" value="25"/>
- <enumerator name="OutCirc" value="26"/>
- <enumerator name="InOutCirc" value="27"/>
- <enumerator name="OutInCirc" value="28"/>
- <enumerator name="InElastic" value="29"/>
- <enumerator name="OutElastic" value="30"/>
- <enumerator name="InOutElastic" value="31"/>
- <enumerator name="OutInElastic" value="32"/>
- <enumerator name="InBack" value="33"/>
- <enumerator name="OutBack" value="34"/>
- <enumerator name="InOutBack" value="35"/>
- <enumerator name="OutInBack" value="36"/>
- <enumerator name="InBounce" value="37"/>
- <enumerator name="OutBounce" value="38"/>
- <enumerator name="InOutBounce" value="39"/>
- <enumerator name="OutInBounce" value="40"/>
- <enumerator name="InCurve" value="41"/>
- <enumerator name="OutCurve" value="42"/>
- <enumerator name="SineCurve" value="43"/>
- <enumerator name="CosineCurve" value="44"/>
- </enum>
- <property name="type" type="Type"/>
- <property name="amplitude" type="qreal"/>
- <property name="overshoot" type="qreal"/>
- <property name="period" type="qreal"/>
- </type>
- <type name="Qt.Flickable" version="4.7" defaultProperty="flickableData" extends="Qt.Item">
- <enum name="BoundsBehavior">
- <enumerator name="StopAtBounds" value="0"/>
- <enumerator name="DragOverBounds" value="1"/>
- <enumerator name="DragAndOvershootBounds" value="2"/>
- </enum>
- <enum name="FlickableDirection">
- <enumerator name="AutoFlickDirection" value="0"/>
- <enumerator name="HorizontalFlick" value="1"/>
- <enumerator name="VerticalFlick" value="2"/>
- <enumerator name="HorizontalAndVerticalFlick" value="3"/>
- </enum>
- <property name="contentWidth" type="qreal"/>
- <property name="contentHeight" type="qreal"/>
- <property name="contentX" type="qreal"/>
- <property name="contentY" type="qreal"/>
- <property name="horizontalVelocity" type="qreal"/>
- <property name="verticalVelocity" type="qreal"/>
- <property name="overShoot" type="bool"/>
- <property name="boundsBehavior" type="BoundsBehavior"/>
- <property name="maximumFlickVelocity" type="qreal"/>
- <property name="flickDeceleration" type="qreal"/>
- <property name="moving" type="bool"/>
- <property name="movingHorizontally" type="bool"/>
- <property name="movingVertically" type="bool"/>
- <property name="flicking" type="bool"/>
- <property name="flickingHorizontally" type="bool"/>
- <property name="flickingVertically" type="bool"/>
- <property name="flickDirection" type="FlickableDirection"/>
- <property name="flickableDirection" type="FlickableDirection"/>
- <property name="interactive" type="bool"/>
- <property name="pressDelay" type="int"/>
- <property name="atXEnd" type="bool"/>
- <property name="atYEnd" type="bool"/>
- <property name="atXBeginning" type="bool"/>
- <property name="atYBeginning" type="bool"/>
- <property name="visibleArea" type="QDeclarativeFlickableVisibleArea"/>
- <property name="flickableData" type="Qt.QtObject" isList="true"/>
- <property name="flickableChildren" type="QGraphicsObject" isList="true"/>
- <signal name="contentWidthChanged"/>
- <signal name="contentHeightChanged"/>
- <signal name="contentXChanged"/>
- <signal name="contentYChanged"/>
- <signal name="movingChanged"/>
- <signal name="movingHorizontallyChanged"/>
- <signal name="movingVerticallyChanged"/>
- <signal name="flickingChanged"/>
- <signal name="flickingHorizontallyChanged"/>
- <signal name="flickingVerticallyChanged"/>
- <signal name="horizontalVelocityChanged"/>
- <signal name="verticalVelocityChanged"/>
- <signal name="isAtBoundaryChanged"/>
- <signal name="pageChanged"/>
- <signal name="flickableDirectionChanged"/>
- <signal name="interactiveChanged"/>
- <signal name="overShootChanged"/>
- <signal name="boundsBehaviorChanged"/>
- <signal name="maximumFlickVelocityChanged"/>
- <signal name="flickDecelerationChanged"/>
- <signal name="pressDelayChanged"/>
- <signal name="movementStarted"/>
- <signal name="movementEnded"/>
- <signal name="flickStarted"/>
- <signal name="flickEnded"/>
- </type>
- <type name="Qt.Flipable" version="4.7" defaultProperty="data" extends="Qt.Item">
- <enum name="Side">
- <enumerator name="Front" value="0"/>
- <enumerator name="Back" value="1"/>
- </enum>
- <property name="front" type="QGraphicsObject"/>
- <property name="back" type="QGraphicsObject"/>
- <property name="side" type="Side"/>
- <signal name="sideChanged"/>
- </type>
- <type name="Qt.Flow" version="4.7" defaultProperty="data" extends="QDeclarativeBasePositioner">
- <enum name="Flow">
- <enumerator name="LeftToRight" value="0"/>
- <enumerator name="TopToBottom" value="1"/>
- </enum>
- <property name="flow" type="Flow"/>
- <signal name="flowChanged"/>
- </type>
- <type name="Qt.FocusPanel" version="4.7" defaultProperty="data" extends="Qt.Item">
- <property name="active" type="bool"/>
- <signal name="activeChanged"/>
- </type>
- <type name="Qt.FocusScope" version="4.7" defaultProperty="data" extends="Qt.Item"/>
- <type name="Qt.Font" version="4.7" extends="QDeclarativeValueType">
- <enum name="FontWeight">
- <enumerator name="Light" value="25"/>
- <enumerator name="Normal" value="50"/>
- <enumerator name="DemiBold" value="63"/>
- <enumerator name="Bold" value="75"/>
- <enumerator name="Black" value="87"/>
- </enum>
- <enum name="Capitalization">
- <enumerator name="MixedCase" value="0"/>
- <enumerator name="AllUppercase" value="1"/>
- <enumerator name="AllLowercase" value="2"/>
- <enumerator name="SmallCaps" value="3"/>
- <enumerator name="Capitalize" value="4"/>
- </enum>
- <property name="family" type="string"/>
- <property name="bold" type="bool"/>
- <property name="weight" type="FontWeight"/>
- <property name="italic" type="bool"/>
- <property name="underline" type="bool"/>
- <property name="overline" type="bool"/>
- <property name="strikeout" type="bool"/>
- <property name="pointSize" type="qreal"/>
- <property name="pixelSize" type="int"/>
- <property name="capitalization" type="Capitalization"/>
- <property name="letterSpacing" type="qreal"/>
- <property name="wordSpacing" type="qreal"/>
- </type>
- <type name="Qt.FontLoader" version="4.7" extends="Qt.QtObject">
- <enum name="Status">
- <enumerator name="Null" value="0"/>
- <enumerator name="Ready" value="1"/>
- <enumerator name="Loading" value="2"/>
- <enumerator name="Error" value="3"/>
- </enum>
- <property name="source" type="QUrl"/>
- <property name="name" type="string"/>
- <property name="status" type="Status"/>
- <signal name="nameChanged"/>
- <signal name="statusChanged"/>
- </type>
- <type name="Qt.Gradient" version="4.7" defaultProperty="stops" extends="Qt.QtObject">
- <property name="stops" type="Qt.GradientStop" isList="true"/>
- <signal name="updated"/>
- </type>
- <type name="Qt.GradientStop" version="4.7" extends="Qt.QtObject">
- <property name="position" type="qreal"/>
- <property name="color" type="QColor"/>
- </type>
- <type name="Qt.Grid" version="4.7" defaultProperty="data" extends="QDeclarativeBasePositioner">
- <enum name="Flow">
- <enumerator name="LeftToRight" value="0"/>
- <enumerator name="TopToBottom" value="1"/>
- </enum>
- <property name="rows" type="int"/>
- <property name="columns" type="int"/>
- <property name="flow" type="Flow"/>
- <signal name="rowsChanged"/>
- <signal name="columnsChanged"/>
- <signal name="flowChanged"/>
- </type>
- <type name="Qt.GridView" version="4.7" defaultProperty="data" extends="Qt.Flickable">
- <enum name="HighlightRangeMode">
- <enumerator name="NoHighlightRange" value="0"/>
- <enumerator name="ApplyRange" value="1"/>
- <enumerator name="StrictlyEnforceRange" value="2"/>
- </enum>
- <enum name="Flow">
- <enumerator name="LeftToRight" value="0"/>
- <enumerator name="TopToBottom" value="1"/>
- </enum>
- <enum name="SnapMode">
- <enumerator name="NoSnap" value="0"/>
- <enumerator name="SnapToRow" value="1"/>
- <enumerator name="SnapOneRow" value="2"/>
- </enum>
- <enum name="PositionMode">
- <enumerator name="Beginning" value="0"/>
- <enumerator name="Center" value="1"/>
- <enumerator name="End" value="2"/>
- <enumerator name="Visible" value="3"/>
- <enumerator name="Contain" value="4"/>
- </enum>
- <property name="model" type="QVariant"/>
- <property name="delegate" type="Qt.Component"/>
- <property name="currentIndex" type="int"/>
- <property name="currentItem" type="Qt.Item"/>
- <property name="count" type="int"/>
- <property name="highlight" type="Qt.Component"/>
- <property name="highlightItem" type="Qt.Item"/>
- <property name="highlightFollowsCurrentItem" type="bool"/>
- <property name="highlightMoveDuration" type="int"/>
- <property name="preferredHighlightBegin" type="qreal"/>
- <property name="preferredHighlightEnd" type="qreal"/>
- <property name="highlightRangeMode" type="HighlightRangeMode"/>
- <property name="flow" type="Flow"/>
- <property name="keyNavigationWraps" type="bool"/>
- <property name="cacheBuffer" type="int"/>
- <property name="cellWidth" type="int"/>
- <property name="cellHeight" type="int"/>
- <property name="snapMode" type="SnapMode"/>
- <signal name="countChanged"/>
- <signal name="currentIndexChanged"/>
- <signal name="cellWidthChanged"/>
- <signal name="cellHeightChanged"/>
- <signal name="highlightChanged"/>
- <signal name="highlightItemChanged"/>
- <signal name="preferredHighlightBeginChanged"/>
- <signal name="preferredHighlightEndChanged"/>
- <signal name="highlightRangeModeChanged"/>
- <signal name="highlightMoveDurationChanged"/>
- <signal name="modelChanged"/>
- <signal name="delegateChanged"/>
- <signal name="flowChanged"/>
- <signal name="keyNavigationWrapsChanged"/>
- <signal name="cacheBufferChanged"/>
- <signal name="snapModeChanged"/>
- <method name="moveCurrentIndexUp"/>
- <method name="moveCurrentIndexDown"/>
- <method name="moveCurrentIndexLeft"/>
- <method name="moveCurrentIndexRight"/>
- <method name="positionViewAtIndex">
- <param name="index" type="int"/>
- <param name="mode" type="int"/>
- </method>
- <method name="indexAt" type="int">
- <param name="x" type="int"/>
- <param name="y" type="int"/>
- </method>
- </type>
- <type name="Qt.Image" version="4.7" defaultProperty="data" extends="QDeclarativeImageBase">
- <enum name="FillMode">
- <enumerator name="Stretch" value="0"/>
- <enumerator name="PreserveAspectFit" value="1"/>
- <enumerator name="PreserveAspectCrop" value="2"/>
- <enumerator name="Tile" value="3"/>
- <enumerator name="TileVertically" value="4"/>
- <enumerator name="TileHorizontally" value="5"/>
- </enum>
- <property name="pixmap" type="QPixmap"/>
- <property name="fillMode" type="FillMode"/>
- <property name="paintedWidth" type="qreal"/>
- <property name="paintedHeight" type="qreal"/>
- <signal name="pixmapChanged"/>
- <signal name="fillModeChanged"/>
- <signal name="paintedGeometryChanged"/>
- </type>
- <type name="Qt.IntValidator" version="4.7" extends="QValidator">
- <property name="bottom" type="int"/>
- <property name="top" type="int"/>
- </type>
- <type name="Qt.Item" version="4.7" defaultProperty="data" extends="QGraphicsObject">
- <enum name="TransformOrigin">
- <enumerator name="TopLeft" value="0"/>
- <enumerator name="Top" value="1"/>
- <enumerator name="TopRight" value="2"/>
- <enumerator name="Left" value="3"/>
- <enumerator name="Center" value="4"/>
- <enumerator name="Right" value="5"/>
- <enumerator name="BottomLeft" value="6"/>
- <enumerator name="Bottom" value="7"/>
- <enumerator name="BottomRight" value="8"/>
- </enum>
- <property name="parent" type="Qt.Item"/>
- <property name="data" type="Qt.QtObject" isList="true"/>
- <property name="resources" type="Qt.QtObject" isList="true"/>
- <property name="states" type="Qt.State" isList="true"/>
- <property name="transitions" type="Qt.Transition" isList="true"/>
- <property name="state" type="string"/>
- <property name="childrenRect" type="QRectF"/>
- <property name="anchors" type="QDeclarativeAnchors"/>
- <property name="left" type="QDeclarativeAnchorLine"/>
- <property name="right" type="QDeclarativeAnchorLine"/>
- <property name="horizontalCenter" type="QDeclarativeAnchorLine"/>
- <property name="top" type="QDeclarativeAnchorLine"/>
- <property name="bottom" type="QDeclarativeAnchorLine"/>
- <property name="verticalCenter" type="QDeclarativeAnchorLine"/>
- <property name="baseline" type="QDeclarativeAnchorLine"/>
- <property name="baselineOffset" type="qreal"/>
- <property name="clip" type="bool"/>
- <property name="focus" type="bool"/>
- <property name="wantsFocus" type="bool"/>
- <property name="transform" type="QGraphicsTransform" isList="true"/>
- <property name="transformOrigin" type="TransformOrigin"/>
- <property name="smooth" type="bool"/>
- <signal name="childrenChanged"/>
- <signal name="childrenRectChanged">
- <param type="QRectF"/>
- </signal>
- <signal name="baselineOffsetChanged">
- <param type="qreal"/>
- </signal>
- <signal name="stateChanged">
- <param type="string"/>
- </signal>
- <signal name="focusChanged">
- <param type="bool"/>
- </signal>
- <signal name="wantsFocusChanged">
- <param type="bool"/>
- </signal>
- <signal name="parentChanged">
- <param type="Qt.Item"/>
- </signal>
- <signal name="transformOriginChanged">
- <param type="TransformOrigin"/>
- </signal>
- <signal name="smoothChanged">
- <param type="bool"/>
- </signal>
- <signal name="clipChanged">
- <param type="bool"/>
- </signal>
- <method name="mapFromItem" type="QScriptValue">
- <param name="item" type="QScriptValue"/>
- <param name="x" type="qreal"/>
- <param name="y" type="qreal"/>
- </method>
- <method name="mapToItem" type="QScriptValue">
- <param name="item" type="QScriptValue"/>
- <param name="x" type="qreal"/>
- <param name="y" type="qreal"/>
- </method>
- <method name="forceFocus"/>
- </type>
- <type name="Qt.KeyNavigation" version="4.7" extends="Qt.QtObject">
- <enum name="Priority">
- <enumerator name="BeforeItem" value="0"/>
- <enumerator name="AfterItem" value="1"/>
- </enum>
- <property name="left" type="Qt.Item"/>
- <property name="right" type="Qt.Item"/>
- <property name="up" type="Qt.Item"/>
- <property name="down" type="Qt.Item"/>
- <property name="tab" type="Qt.Item"/>
- <property name="backtab" type="Qt.Item"/>
- <property name="priority" type="Priority"/>
- <signal name="changed"/>
- <signal name="priorityChanged"/>
- </type>
- <type name="Qt.Keys" version="4.7" extends="Qt.QtObject">
- <enum name="Priority">
- <enumerator name="BeforeItem" value="0"/>
- <enumerator name="AfterItem" value="1"/>
- </enum>
- <property name="enabled" type="bool"/>
- <property name="forwardTo" type="Qt.Item" isList="true"/>
- <property name="priority" type="Priority"/>
- <signal name="enabledChanged"/>
- <signal name="priorityChanged"/>
- <signal name="pressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="released">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="digit0Pressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="digit1Pressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="digit2Pressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="digit3Pressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="digit4Pressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="digit5Pressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="digit6Pressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="digit7Pressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="digit8Pressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="digit9Pressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="leftPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="rightPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="upPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="downPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="tabPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="backtabPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="asteriskPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="numberSignPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="escapePressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="returnPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="enterPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="deletePressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="spacePressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="backPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="cancelPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="selectPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="yesPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="noPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="context1Pressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="context2Pressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="context3Pressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="context4Pressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="callPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="hangupPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="flipPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="menuPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="volumeUpPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- <signal name="volumeDownPressed">
- <param name="event" type="QDeclarativeKeyEvent"/>
- </signal>
- </type>
- <type name="Qt.LayoutItem" version="4.7" defaultProperty="data" extends="Qt.Item">
- <property name="maximumSize" type="QSizeF"/>
- <property name="minimumSize" type="QSizeF"/>
- <property name="preferredSize" type="QSizeF"/>
- <signal name="maximumSizeChanged"/>
- <signal name="minimumSizeChanged"/>
- <signal name="preferredSizeChanged"/>
- </type>
- <type name="Qt.ListElement" version="4.7" extends="Qt.QtObject"/>
- <type name="Qt.ListModel" version="4.7" extends="QListModelInterface">
- <property name="count" type="int"/>
- <signal name="countChanged"/>
- <method name="clear"/>
- <method name="remove">
- <param name="index" type="int"/>
- </method>
- <method name="append">
- <param type="QScriptValue"/>
- </method>
- <method name="insert">
- <param name="index" type="int"/>
- <param type="QScriptValue"/>
- </method>
- <method name="get" type="QScriptValue">
- <param name="index" type="int"/>
- </method>
- <method name="set">
- <param name="index" type="int"/>
- <param type="QScriptValue"/>
- </method>
- <method name="setProperty">
- <param name="index" type="int"/>
- <param name="property" type="string"/>
- <param name="value" type="QVariant"/>
- </method>
- <method name="move">
- <param name="from" type="int"/>
- <param name="to" type="int"/>
- <param name="count" type="int"/>
- </method>
- <method name="sync"/>
- </type>
- <type name="Qt.ListView" version="4.7" defaultProperty="data" extends="Qt.Flickable">
- <enum name="HighlightRangeMode">
- <enumerator name="NoHighlightRange" value="0"/>
- <enumerator name="ApplyRange" value="1"/>
- <enumerator name="StrictlyEnforceRange" value="2"/>
- </enum>
- <enum name="Orientation">
- <enumerator name="Horizontal" value="1"/>
- <enumerator name="Vertical" value="2"/>
- </enum>
- <enum name="SnapMode">
- <enumerator name="NoSnap" value="0"/>
- <enumerator name="SnapToItem" value="1"/>
- <enumerator name="SnapOneItem" value="2"/>
- </enum>
- <enum name="PositionMode">
- <enumerator name="Beginning" value="0"/>
- <enumerator name="Center" value="1"/>
- <enumerator name="End" value="2"/>
- <enumerator name="Visible" value="3"/>
- <enumerator name="Contain" value="4"/>
- </enum>
- <property name="model" type="QVariant"/>
- <property name="delegate" type="Qt.Component"/>
- <property name="currentIndex" type="int"/>
- <property name="currentItem" type="Qt.Item"/>
- <property name="count" type="int"/>
- <property name="highlight" type="Qt.Component"/>
- <property name="highlightItem" type="Qt.Item"/>
- <property name="highlightFollowsCurrentItem" type="bool"/>
- <property name="highlightMoveSpeed" type="qreal"/>
- <property name="highlightMoveDuration" type="int"/>
- <property name="highlightResizeSpeed" type="qreal"/>
- <property name="highlightResizeDuration" type="int"/>
- <property name="preferredHighlightBegin" type="qreal"/>
- <property name="preferredHighlightEnd" type="qreal"/>
- <property name="highlightRangeMode" type="HighlightRangeMode"/>
- <property name="spacing" type="qreal"/>
- <property name="orientation" type="Orientation"/>
- <property name="keyNavigationWraps" type="bool"/>
- <property name="cacheBuffer" type="int"/>
- <property name="section" type="Qt.ViewSection"/>
- <property name="currentSection" type="string"/>
- <property name="snapMode" type="SnapMode"/>
- <property name="header" type="Qt.Component"/>
- <property name="footer" type="Qt.Component"/>
- <signal name="countChanged"/>
- <signal name="spacingChanged"/>
- <signal name="orientationChanged"/>
- <signal name="currentIndexChanged"/>
- <signal name="currentSectionChanged"/>
- <signal name="highlightMoveSpeedChanged"/>
- <signal name="highlightMoveDurationChanged"/>
- <signal name="highlightResizeSpeedChanged"/>
- <signal name="highlightResizeDurationChanged"/>
- <signal name="highlightChanged"/>
- <signal name="highlightItemChanged"/>
- <signal name="modelChanged"/>
- <signal name="delegateChanged"/>
- <signal name="highlightFollowsCurrentItemChanged"/>
- <signal name="preferredHighlightBeginChanged"/>
- <signal name="preferredHighlightEndChanged"/>
- <signal name="highlightRangeModeChanged"/>
- <signal name="keyNavigationWrapsChanged"/>
- <signal name="cacheBufferChanged"/>
- <signal name="snapModeChanged"/>
- <signal name="headerChanged"/>
- <signal name="footerChanged"/>
- <method name="incrementCurrentIndex"/>
- <method name="decrementCurrentIndex"/>
- <method name="positionViewAtIndex">
- <param name="index" type="int"/>
- <param name="mode" type="int"/>
- </method>
- <method name="indexAt" type="int">
- <param name="x" type="int"/>
- <param name="y" type="int"/>
- </method>
- </type>
- <type name="Qt.Loader" version="4.7" defaultProperty="data" extends="Qt.Item">
- <enum name="Status">
- <enumerator name="Null" value="0"/>
- <enumerator name="Ready" value="1"/>
- <enumerator name="Loading" value="2"/>
- <enumerator name="Error" value="3"/>
- </enum>
- <property name="source" type="QUrl"/>
- <property name="sourceComponent" type="Qt.Component"/>
- <property name="item" type="QGraphicsObject"/>
- <property name="status" type="Status"/>
- <property name="progress" type="qreal"/>
- <signal name="itemChanged"/>
- <signal name="sourceChanged"/>
- <signal name="statusChanged"/>
- <signal name="progressChanged"/>
- <signal name="loaded"/>
- </type>
- <type name="Qt.MouseArea" version="4.7" defaultProperty="data" extends="Qt.Item">
- <property name="mouseX" type="qreal"/>
- <property name="mouseY" type="qreal"/>
- <property name="containsMouse" type="bool"/>
- <property name="pressed" type="bool"/>
- <property name="enabled" type="bool"/>
- <property name="pressedButtons" type="Qt.MouseButtons"/>
- <property name="acceptedButtons" type="Qt.MouseButtons"/>
- <property name="hoverEnabled" type="bool"/>
- <property name="drag" type="Qt.Drag"/>
- <signal name="hoveredChanged"/>
- <signal name="pressedChanged"/>
- <signal name="enabledChanged"/>
- <signal name="acceptedButtonsChanged"/>
- <signal name="hoverEnabledChanged"/>
- <signal name="positionChanged">
- <param name="mouse" type="QDeclarativeMouseEvent"/>
- </signal>
- <signal name="mousePositionChanged">
- <param name="mouse" type="QDeclarativeMouseEvent"/>
- </signal>
- <signal name="pressed">
- <param name="mouse" type="QDeclarativeMouseEvent"/>
- </signal>
- <signal name="pressAndHold">
- <param name="mouse" type="QDeclarativeMouseEvent"/>
- </signal>
- <signal name="released">
- <param name="mouse" type="QDeclarativeMouseEvent"/>
- </signal>
- <signal name="clicked">
- <param name="mouse" type="QDeclarativeMouseEvent"/>
- </signal>
- <signal name="doubleClicked">
- <param name="mouse" type="QDeclarativeMouseEvent"/>
- </signal>
- <signal name="entered"/>
- <signal name="exited"/>
- <signal name="canceled"/>
- </type>
- <type name="Qt.NumberAnimation" version="4.7" extends="Qt.PropertyAnimation">
- <property name="from" type="qreal"/>
- <property name="to" type="qreal"/>
- </type>
- <type name="Qt.Package" version="4.7" defaultProperty="data" extends="Qt.QtObject">
- <property name="data" type="Qt.QtObject" isList="true"/>
- </type>
- <type name="Qt.ParallelAnimation" version="4.7" defaultProperty="animations" extends="QDeclarativeAnimationGroup"/>
- <type name="Qt.ParentAnimation" version="4.7" defaultProperty="animations" extends="QDeclarativeAnimationGroup">
- <property name="target" type="Qt.Item"/>
- <property name="newParent" type="Qt.Item"/>
- <property name="via" type="Qt.Item"/>
- <signal name="targetChanged"/>
- <signal name="newParentChanged"/>
- <signal name="viaChanged"/>
- </type>
- <type name="Qt.ParentChange" version="4.7" extends="QDeclarativeStateOperation">
- <property name="target" type="Qt.Item"/>
- <property name="parent" type="Qt.Item"/>
- <property name="x" type="QDeclarativeScriptString"/>
- <property name="y" type="QDeclarativeScriptString"/>
- <property name="width" type="QDeclarativeScriptString"/>
- <property name="height" type="QDeclarativeScriptString"/>
- <property name="scale" type="QDeclarativeScriptString"/>
- <property name="rotation" type="QDeclarativeScriptString"/>
- </type>
- <type name="Qt.Path" version="4.7" defaultProperty="pathElements" extends="Qt.QtObject">
- <property name="pathElements" type="QDeclarativePathElement" isList="true"/>
- <property name="startX" type="qreal"/>
- <property name="startY" type="qreal"/>
- <property name="closed" type="bool"/>
- <signal name="changed"/>
- <signal name="startXChanged"/>
- <signal name="startYChanged"/>
- </type>
- <type name="Qt.PathAttribute" version="4.7" extends="QDeclarativePathElement">
- <property name="name" type="string"/>
- <property name="value" type="qreal"/>
- <signal name="nameChanged"/>
- </type>
- <type name="Qt.PathCubic" version="4.7" extends="QDeclarativeCurve">
- <property name="control1X" type="qreal"/>
- <property name="control1Y" type="qreal"/>
- <property name="control2X" type="qreal"/>
- <property name="control2Y" type="qreal"/>
- </type>
- <type name="Qt.PathLine" version="4.7" extends="QDeclarativeCurve"/>
- <type name="Qt.PathPercent" version="4.7" extends="QDeclarativePathElement">
- <property name="value" type="qreal"/>
- </type>
- <type name="Qt.PathQuad" version="4.7" extends="QDeclarativeCurve">
- <property name="controlX" type="qreal"/>
- <property name="controlY" type="qreal"/>
- </type>
- <type name="Qt.PathView" version="4.7" defaultProperty="data" extends="Qt.Item">
- <enum name="HighlightRangeMode">
- <enumerator name="NoHighlightRange" value="0"/>
- <enumerator name="ApplyRange" value="1"/>
- <enumerator name="StrictlyEnforceRange" value="2"/>
- </enum>
- <property name="model" type="QVariant"/>
- <property name="path" type="Qt.Path"/>
- <property name="currentIndex" type="int"/>
- <property name="offset" type="qreal"/>
- <property name="highlight" type="Qt.Component"/>
- <property name="highlightItem" type="Qt.Item"/>
- <property name="preferredHighlightBegin" type="qreal"/>
- <property name="preferredHighlightEnd" type="qreal"/>
- <property name="highlightRangeMode" type="HighlightRangeMode"/>
- <property name="highlightMoveDuration" type="int"/>
- <property name="dragMargin" type="qreal"/>
- <property name="flickDeceleration" type="qreal"/>
- <property name="interactive" type="bool"/>
- <property name="count" type="int"/>
- <property name="delegate" type="Qt.Component"/>
- <property name="pathItemCount" type="int"/>
- <signal name="currentIndexChanged"/>
- <signal name="offsetChanged"/>
- <signal name="modelChanged"/>
- <signal name="countChanged"/>
- <signal name="pathChanged"/>
- <signal name="preferredHighlightBeginChanged"/>
- <signal name="preferredHighlightEndChanged"/>
- <signal name="highlightRangeModeChanged"/>
- <signal name="dragMarginChanged"/>
- <signal name="snapPositionChanged"/>
- <signal name="delegateChanged"/>
- <signal name="pathItemCountChanged"/>
- <signal name="flickDecelerationChanged"/>
- <signal name="interactiveChanged"/>
- <signal name="highlightChanged"/>
- <signal name="highlightItemChanged"/>
- <signal name="highlightMoveDurationChanged"/>
- <method name="incrementCurrentIndex"/>
- <method name="decrementCurrentIndex"/>
- </type>
- <type name="Qt.PauseAnimation" version="4.7" extends="Qt.Animation">
- <property name="duration" type="int"/>
- <signal name="durationChanged">
- <param type="int"/>
- </signal>
- </type>
- <type name="Qt.PropertyAction" version="4.7" extends="Qt.Animation">
- <property name="target" type="Qt.QtObject"/>
- <property name="property" type="string"/>
- <property name="properties" type="string"/>
- <property name="targets" type="Qt.QtObject" isList="true"/>
- <property name="exclude" type="Qt.QtObject" isList="true"/>
- <property name="value" type="QVariant"/>
- <signal name="valueChanged">
- <param type="QVariant"/>
- </signal>
- <signal name="propertiesChanged">
- <param type="string"/>
- </signal>
- <signal name="targetChanged">
- <param type="Qt.QtObject"/>
- <param type="string"/>
- </signal>
- </type>
- <type name="Qt.PropertyAnimation" version="4.7" extends="Qt.Animation">
- <property name="duration" type="int"/>
- <property name="from" type="QVariant"/>
- <property name="to" type="QVariant"/>
- <property name="easing" type="Qt.Easing"/>
- <property name="target" type="Qt.QtObject"/>
- <property name="property" type="string"/>
- <property name="properties" type="string"/>
- <property name="targets" type="Qt.QtObject" isList="true"/>
- <property name="exclude" type="Qt.QtObject" isList="true"/>
- <signal name="durationChanged">
- <param type="int"/>
- </signal>
- <signal name="fromChanged">
- <param type="QVariant"/>
- </signal>
- <signal name="toChanged">
- <param type="QVariant"/>
- </signal>
- <signal name="easingChanged">
- <param type="Qt.Easing"/>
- </signal>
- <signal name="propertiesChanged">
- <param type="string"/>
- </signal>
- <signal name="targetChanged">
- <param type="Qt.QtObject"/>
- <param type="string"/>
- </signal>
- </type>
- <type name="Qt.PropertyChanges" version="4.7" extends="QDeclarativeStateOperation">
- <property name="target" type="Qt.QtObject"/>
- <property name="restoreEntryValues" type="bool"/>
- <property name="explicit" type="bool"/>
- </type>
- <type name="Qt.QGraphicsWidget" version="4.7" defaultProperty="children" extends="QGraphicsObject">
- <property name="palette" type="QPalette"/>
- <property name="font" type="QFont"/>
- <property name="layoutDirection" type="Qt.LayoutDirection"/>
- <property name="size" type="QSizeF"/>
- <property name="minimumSize" type="QSizeF"/>
- <property name="preferredSize" type="QSizeF"/>
- <property name="maximumSize" type="QSizeF"/>
- <property name="sizePolicy" type="QSizePolicy"/>
- <property name="focusPolicy" type="Qt.FocusPolicy"/>
- <property name="windowFlags" type="Qt.WindowFlags"/>
- <property name="windowTitle" type="string"/>
- <property name="geometry" type="QRectF"/>
- <property name="autoFillBackground" type="bool"/>
- <property name="layout" type="QGraphicsLayout"/>
- <signal name="geometryChanged"/>
- <signal name="layoutChanged"/>
- <method name="close" type="bool"/>
- </type>
- <type name="Qt.QtObject" version="4.7">
- <property name="objectName" type="string"/>
- <signal name="destroyed">
- <param type="Qt.QtObject"/>
- </signal>
- <signal name="destroyed"/>
- <method name="deleteLater"/>
- </type>
- <type name="Qt.Rectangle" version="4.7" defaultProperty="data" extends="Qt.Item">
- <property name="color" type="QColor"/>
- <property name="gradient" type="Qt.Gradient"/>
- <property name="border" type="QDeclarativePen"/>
- <property name="radius" type="qreal"/>
- <signal name="colorChanged"/>
- <signal name="radiusChanged"/>
- </type>
- <type name="Qt.RegExpValidator" version="4.7" extends="QValidator">
- <property name="regExp" type="QRegExp"/>
- </type>
- <type name="Qt.Repeater" version="4.7" defaultProperty="delegate" extends="Qt.Item">
- <property name="model" type="QVariant"/>
- <property name="delegate" type="Qt.Component"/>
- <property name="count" type="int"/>
- <signal name="modelChanged"/>
- <signal name="delegateChanged"/>
- <signal name="countChanged"/>
- </type>
- <type name="Qt.Rotation" version="4.7" extends="QGraphicsTransform">
- <property name="origin" type="QVector3D"/>
- <property name="angle" type="qreal"/>
- <property name="axis" type="QVector3D"/>
- <signal name="originChanged"/>
- <signal name="angleChanged"/>
- <signal name="axisChanged"/>
- </type>
- <type name="Qt.RotationAnimation" version="4.7" extends="Qt.PropertyAnimation">
- <enum name="RotationDirection">
- <enumerator name="Numerical" value="0"/>
- <enumerator name="Shortest" value="1"/>
- <enumerator name="Clockwise" value="2"/>
- <enumerator name="Counterclockwise" value="3"/>
- </enum>
- <property name="from" type="qreal"/>
- <property name="to" type="qreal"/>
- <property name="direction" type="RotationDirection"/>
- <signal name="directionChanged"/>
- </type>
- <type name="Qt.Row" version="4.7" defaultProperty="data" extends="QDeclarativeBasePositioner"/>
- <type name="Qt.Scale" version="4.7" extends="QGraphicsTransform">
- <property name="origin" type="QVector3D"/>
- <property name="xScale" type="qreal"/>
- <property name="yScale" type="qreal"/>
- <property name="zScale" type="qreal"/>
- <signal name="originChanged"/>
- <signal name="scaleChanged"/>
- </type>
- <type name="Qt.ScriptAction" version="4.7" extends="Qt.Animation">
- <property name="script" type="QDeclarativeScriptString"/>
- <property name="scriptName" type="string"/>
- </type>
- <type name="Qt.SequentialAnimation" version="4.7" defaultProperty="animations" extends="QDeclarativeAnimationGroup"/>
- <type name="Qt.SmoothedAnimation" version="4.7" extends="Qt.NumberAnimation">
- <enum name="ReversingMode">
- <enumerator name="Eased" value="0"/>
- <enumerator name="Immediate" value="1"/>
- <enumerator name="Sync" value="2"/>
- </enum>
- <property name="velocity" type="qreal"/>
- <property name="reversingMode" type="ReversingMode"/>
- <property name="maximumEasingTime" type="qreal"/>
- <signal name="velocityChanged"/>
- <signal name="reversingModeChanged"/>
- <signal name="maximumEasingTimeChanged"/>
- </type>
- <type name="Qt.SmoothedFollow" version="4.7" extends="Qt.QtObject">
- <enum name="ReversingMode">
- <enumerator name="Eased" value="0"/>
- <enumerator name="Immediate" value="1"/>
- <enumerator name="Sync" value="2"/>
- </enum>
- <property name="to" type="qreal"/>
- <property name="velocity" type="qreal"/>
- <property name="duration" type="int"/>
- <property name="reversingMode" type="ReversingMode"/>
- <property name="maximumEasingTime" type="qreal"/>
- <property name="enabled" type="bool"/>
- <signal name="velocityChanged"/>
- <signal name="durationChanged"/>
- <signal name="reversingModeChanged"/>
- <signal name="maximumEasingTimeChanged"/>
- <signal name="enabledChanged"/>
- </type>
- <type name="Qt.SpringFollow" version="4.7" extends="Qt.QtObject">
- <property name="to" type="qreal"/>
- <property name="velocity" type="qreal"/>
- <property name="spring" type="qreal"/>
- <property name="damping" type="qreal"/>
- <property name="epsilon" type="qreal"/>
- <property name="enabled" type="bool"/>
- <property name="value" type="qreal"/>
- <property name="modulus" type="qreal"/>
- <property name="mass" type="qreal"/>
- <property name="inSync" type="bool"/>
- <signal name="valueChanged">
- <param type="qreal"/>
- </signal>
- <signal name="modulusChanged"/>
- <signal name="massChanged"/>
- <signal name="syncChanged"/>
- </type>
- <type name="Qt.State" version="4.7" defaultProperty="changes" extends="Qt.QtObject">
- <property name="name" type="string"/>
- <property name="when" type="QDeclarativeBinding"/>
- <property name="extend" type="string"/>
- <property name="changes" type="QDeclarativeStateOperation" isList="true"/>
- <signal name="completed"/>
- </type>
- <type name="Qt.StateChangeScript" version="4.7" extends="QDeclarativeStateOperation">
- <property name="script" type="QDeclarativeScriptString"/>
- <property name="name" type="string"/>
- </type>
- <type name="Qt.StateGroup" version="4.7" extends="Qt.QtObject">
- <property name="state" type="string"/>
- <property name="states" type="Qt.State" isList="true"/>
- <property name="transitions" type="Qt.Transition" isList="true"/>
- <signal name="stateChanged">
- <param type="string"/>
- </signal>
- </type>
- <type name="Qt.SystemPalette" version="4.7" extends="Qt.QtObject">
- <enum name="ColorGroup">
- <enumerator name="Active" value="0"/>
- <enumerator name="Inactive" value="2"/>
- <enumerator name="Disabled" value="1"/>
- </enum>
- <property name="colorGroup" type="QDeclarativeSystemPalette.ColorGroup"/>
- <property name="window" type="QColor"/>
- <property name="windowText" type="QColor"/>
- <property name="base" type="QColor"/>
- <property name="text" type="QColor"/>
- <property name="alternateBase" type="QColor"/>
- <property name="button" type="QColor"/>
- <property name="buttonText" type="QColor"/>
- <property name="light" type="QColor"/>
- <property name="midlight" type="QColor"/>
- <property name="dark" type="QColor"/>
- <property name="mid" type="QColor"/>
- <property name="shadow" type="QColor"/>
- <property name="highlight" type="QColor"/>
- <property name="highlightedText" type="QColor"/>
- <signal name="paletteChanged"/>
- </type>
- <type name="Qt.Text" version="4.7" defaultProperty="data" extends="Qt.Item">
- <enum name="HAlignment">
- <enumerator name="AlignLeft" value="1"/>
- <enumerator name="AlignRight" value="2"/>
- <enumerator name="AlignHCenter" value="4"/>
- </enum>
- <enum name="VAlignment">
- <enumerator name="AlignTop" value="32"/>
- <enumerator name="AlignBottom" value="64"/>
- <enumerator name="AlignVCenter" value="128"/>
- </enum>
- <enum name="TextStyle">
- <enumerator name="Normal" value="0"/>
- <enumerator name="Outline" value="1"/>
- <enumerator name="Raised" value="2"/>
- <enumerator name="Sunken" value="3"/>
- </enum>
- <enum name="TextFormat">
- <enumerator name="PlainText" value="0"/>
- <enumerator name="RichText" value="1"/>
- <enumerator name="AutoText" value="2"/>
- <enumerator name="StyledText" value="4"/>
- </enum>
- <enum name="TextElideMode">
- <enumerator name="ElideLeft" value="0"/>
- <enumerator name="ElideRight" value="1"/>
- <enumerator name="ElideMiddle" value="2"/>
- <enumerator name="ElideNone" value="3"/>
- </enum>
- <enum name="WrapMode">
- <enumerator name="NoWrap" value="0"/>
- <enumerator name="WordWrap" value="1"/>
- <enumerator name="WrapAnywhere" value="3"/>
- <enumerator name="WrapAtWordBoundaryOrAnywhere" value="4"/>
- <enumerator name="Wrap" value="4"/>
- </enum>
- <property name="text" type="string"/>
- <property name="font" type="QFont"/>
- <property name="color" type="QColor"/>
- <property name="style" type="TextStyle"/>
- <property name="styleColor" type="QColor"/>
- <property name="horizontalAlignment" type="HAlignment"/>
- <property name="verticalAlignment" type="VAlignment"/>
- <property name="wrapMode" type="WrapMode"/>
- <property name="textFormat" type="TextFormat"/>
- <property name="elide" type="TextElideMode"/>
- <property name="paintedWidth" type="qreal"/>
- <property name="paintedHeight" type="qreal"/>
- <signal name="textChanged">
- <param name="text" type="string"/>
- </signal>
- <signal name="linkActivated">
- <param name="link" type="string"/>
- </signal>
- <signal name="fontChanged">
- <param name="font" type="QFont"/>
- </signal>
- <signal name="colorChanged">
- <param name="color" type="QColor"/>
- </signal>
- <signal name="styleChanged">
- <param name="style" type="TextStyle"/>
- </signal>
- <signal name="styleColorChanged">
- <param name="color" type="QColor"/>
- </signal>
- <signal name="horizontalAlignmentChanged">
- <param name="alignment" type="HAlignment"/>
- </signal>
- <signal name="verticalAlignmentChanged">
- <param name="alignment" type="VAlignment"/>
- </signal>
- <signal name="wrapModeChanged"/>
- <signal name="textFormatChanged">
- <param name="textFormat" type="TextFormat"/>
- </signal>
- <signal name="elideModeChanged">
- <param name="mode" type="TextElideMode"/>
- </signal>
- <signal name="paintedSizeChanged"/>
- </type>
- <type name="Qt.TextEdit" version="4.7" defaultProperty="data" extends="QDeclarativePaintedItem">
- <enum name="HAlignment">
- <enumerator name="AlignLeft" value="1"/>
- <enumerator name="AlignRight" value="2"/>
- <enumerator name="AlignHCenter" value="4"/>
- </enum>
- <enum name="VAlignment">
- <enumerator name="AlignTop" value="32"/>
- <enumerator name="AlignBottom" value="64"/>
- <enumerator name="AlignVCenter" value="128"/>
- </enum>
- <enum name="TextFormat">
- <enumerator name="PlainText" value="0"/>
- <enumerator name="RichText" value="1"/>
- <enumerator name="AutoText" value="2"/>
- </enum>
- <enum name="WrapMode">
- <enumerator name="NoWrap" value="0"/>
- <enumerator name="WordWrap" value="1"/>
- <enumerator name="WrapAnywhere" value="3"/>
- <enumerator name="WrapAtWordBoundaryOrAnywhere" value="4"/>
- <enumerator name="Wrap" value="4"/>
- </enum>
- <property name="text" type="string"/>
- <property name="color" type="QColor"/>
- <property name="selectionColor" type="QColor"/>
- <property name="selectedTextColor" type="QColor"/>
- <property name="font" type="QFont"/>
- <property name="horizontalAlignment" type="HAlignment"/>
- <property name="verticalAlignment" type="VAlignment"/>
- <property name="wrapMode" type="WrapMode"/>
- <property name="paintedWidth" type="qreal"/>
- <property name="paintedHeight" type="qreal"/>
- <property name="textFormat" type="TextFormat"/>
- <property name="readOnly" type="bool"/>
- <property name="cursorVisible" type="bool"/>
- <property name="cursorPosition" type="int"/>
- <property name="cursorRectangle" type="QRect"/>
- <property name="cursorDelegate" type="Qt.Component"/>
- <property name="selectionStart" type="int"/>
- <property name="selectionEnd" type="int"/>
- <property name="selectedText" type="string"/>
- <property name="focusOnPress" type="bool"/>
- <property name="showInputPanelOnFocus" type="bool"/>
- <property name="persistentSelection" type="bool"/>
- <property name="textMargin" type="qreal"/>
- <property name="inputMethodHints" type="Qt.InputMethodHints"/>
- <property name="selectByMouse" type="bool"/>
- <signal name="textChanged">
- <param type="string"/>
- </signal>
- <signal name="paintedSizeChanged"/>
- <signal name="cursorPositionChanged"/>
- <signal name="cursorRectangleChanged"/>
- <signal name="selectionStartChanged"/>
- <signal name="selectionEndChanged"/>
- <signal name="selectionChanged"/>
- <signal name="colorChanged">
- <param name="color" type="QColor"/>
- </signal>
- <signal name="selectionColorChanged">
- <param name="color" type="QColor"/>
- </signal>
- <signal name="selectedTextColorChanged">
- <param name="color" type="QColor"/>
- </signal>
- <signal name="fontChanged">
- <param name="font" type="QFont"/>
- </signal>
- <signal name="horizontalAlignmentChanged">
- <param name="alignment" type="HAlignment"/>
- </signal>
- <signal name="verticalAlignmentChanged">
- <param name="alignment" type="VAlignment"/>
- </signal>
- <signal name="wrapModeChanged"/>
- <signal name="textFormatChanged">
- <param name="textFormat" type="TextFormat"/>
- </signal>
- <signal name="readOnlyChanged">
- <param name="isReadOnly" type="bool"/>
- </signal>
- <signal name="cursorVisibleChanged">
- <param name="isCursorVisible" type="bool"/>
- </signal>
- <signal name="cursorDelegateChanged"/>
- <signal name="focusOnPressChanged">
- <param name="focusIsPressed" type="bool"/>
- </signal>
- <signal name="persistentSelectionChanged">
- <param name="isPersistentSelection" type="bool"/>
- </signal>
- <signal name="textMarginChanged">
- <param name="textMargin" type="qreal"/>
- </signal>
- <signal name="selectByMouseChanged">
- <param name="selectByMouse" type="bool"/>
- </signal>
- <signal name="showInputPanelOnFocusChanged">
- <param name="showOnFocus" type="bool"/>
- </signal>
- <method name="selectAll"/>
- <method name="openSoftwareInputPanel"/>
- <method name="closeSoftwareInputPanel"/>
- </type>
- <type name="Qt.TextInput" version="4.7" defaultProperty="data" extends="QDeclarativePaintedItem">
- <enum name="EchoMode">
- <enumerator name="Normal" value="0"/>
- <enumerator name="NoEcho" value="1"/>
- <enumerator name="Password" value="2"/>
- <enumerator name="PasswordEchoOnEdit" value="3"/>
- </enum>
- <enum name="HAlignment">
- <enumerator name="AlignLeft" value="1"/>
- <enumerator name="AlignRight" value="2"/>
- <enumerator name="AlignHCenter" value="4"/>
- </enum>
- <property name="text" type="string"/>
- <property name="color" type="QColor"/>
- <property name="selectionColor" type="QColor"/>
- <property name="selectedTextColor" type="QColor"/>
- <property name="font" type="QFont"/>
- <property name="horizontalAlignment" type="HAlignment"/>
- <property name="readOnly" type="bool"/>
- <property name="cursorVisible" type="bool"/>
- <property name="cursorPosition" type="int"/>
- <property name="cursorRect" type="QRect"/>
- <property name="cursorDelegate" type="Qt.Component"/>
- <property name="selectionStart" type="int"/>
- <property name="selectionEnd" type="int"/>
- <property name="selectedText" type="string"/>
- <property name="maximumLength" type="int"/>
- <property name="validator" type="QValidator"/>
- <property name="inputMask" type="string"/>
- <property name="inputMethodHints" type="Qt.InputMethodHints"/>
- <property name="acceptableInput" type="bool"/>
- <property name="echoMode" type="EchoMode"/>
- <property name="focusOnPress" type="bool"/>
- <property name="showInputPanelOnFocus" type="bool"/>
- <property name="passwordCharacter" type="string"/>
- <property name="displayText" type="string"/>
- <property name="autoScroll" type="bool"/>
- <property name="selectByMouse" type="bool"/>
- <signal name="textChanged"/>
- <signal name="cursorPositionChanged"/>
- <signal name="selectionStartChanged"/>
- <signal name="selectionEndChanged"/>
- <signal name="selectedTextChanged"/>
- <signal name="accepted"/>
- <signal name="acceptableInputChanged"/>
- <signal name="colorChanged">
- <param name="color" type="QColor"/>
- </signal>
- <signal name="selectionColorChanged">
- <param name="color" type="QColor"/>
- </signal>
- <signal name="selectedTextColorChanged">
- <param name="color" type="QColor"/>
- </signal>
- <signal name="fontChanged">
- <param name="font" type="QFont"/>
- </signal>
- <signal name="horizontalAlignmentChanged">
- <param name="alignment" type="HAlignment"/>
- </signal>
- <signal name="readOnlyChanged">
- <param name="isReadOnly" type="bool"/>
- </signal>
- <signal name="cursorVisibleChanged">
- <param name="isCursorVisible" type="bool"/>
- </signal>
- <signal name="cursorDelegateChanged"/>
- <signal name="maximumLengthChanged">
- <param name="maximumLength" type="int"/>
- </signal>
- <signal name="validatorChanged"/>
- <signal name="inputMaskChanged">
- <param name="inputMask" type="string"/>
- </signal>
- <signal name="echoModeChanged">
- <param name="echoMode" type="EchoMode"/>
- </signal>
- <signal name="passwordCharacterChanged"/>
- <signal name="displayTextChanged">
- <param name="text" type="string"/>
- </signal>
- <signal name="focusOnPressChanged">
- <param name="focusOnPress" type="bool"/>
- </signal>
- <signal name="autoScrollChanged">
- <param name="autoScroll" type="bool"/>
- </signal>
- <signal name="selectByMouseChanged">
- <param name="selectByMouse" type="bool"/>
- </signal>
- <signal name="showInputPanelOnFocusChanged">
- <param name="showOnFocus" type="bool"/>
- </signal>
- <method name="selectAll"/>
- <method name="xToPosition" type="int">
- <param name="x" type="int"/>
- </method>
- <method name="moveCursorSelection">
- <param name="pos" type="int"/>
- </method>
- <method name="openSoftwareInputPanel"/>
- <method name="closeSoftwareInputPanel"/>
- </type>
- <type name="Qt.Timer" version="4.7" extends="Qt.QtObject">
- <property name="interval" type="int"/>
- <property name="running" type="bool"/>
- <property name="repeat" type="bool"/>
- <property name="triggeredOnStart" type="bool"/>
- <property name="parent" type="Qt.QtObject"/>
- <signal name="triggered"/>
- <signal name="runningChanged"/>
- <signal name="intervalChanged"/>
- <signal name="repeatChanged"/>
- <signal name="triggeredOnStartChanged"/>
- <method name="start"/>
- <method name="stop"/>
- <method name="restart"/>
- </type>
- <type name="Qt.Transition" version="4.7" defaultProperty="animations" extends="Qt.QtObject">
- <property name="from" type="string"/>
- <property name="to" type="string"/>
- <property name="reversible" type="bool"/>
- <property name="animations" type="Qt.Animation" isList="true"/>
- <signal name="fromChanged"/>
- <signal name="toChanged"/>
- <signal name="reversibleChanged"/>
- </type>
- <type name="Qt.Translate" version="4.7" extends="QGraphicsTransform">
- <property name="x" type="qreal"/>
- <property name="y" type="qreal"/>
- <signal name="positionChanged"/>
- </type>
- <type name="Qt.Vector3dAnimation" version="4.7" extends="Qt.PropertyAnimation">
- <property name="from" type="QVector3D"/>
- <property name="to" type="QVector3D"/>
- </type>
- <type name="Qt.ViewSection" version="4.7" extends="Qt.QtObject">
- <enum name="SectionCriteria">
- <enumerator name="FullString" value="0"/>
- <enumerator name="FirstCharacter" value="1"/>
- </enum>
- <property name="property" type="string"/>
- <property name="criteria" type="SectionCriteria"/>
- <property name="delegate" type="Qt.Component"/>
- <signal name="changed"/>
- <signal name="delegateChanged"/>
- </type>
- <type name="Qt.VisualDataModel" version="4.7" defaultProperty="delegate" extends="QDeclarativeVisualModel">
- <property name="model" type="QVariant"/>
- <property name="delegate" type="Qt.Component"/>
- <property name="part" type="string"/>
- <property name="parts" type="Qt.QtObject"/>
- <property name="rootIndex" type="QVariant"/>
- <signal name="createdPackage">
- <param name="index" type="int"/>
- <param name="package" type="Qt.Package"/>
- </signal>
- <signal name="destroyingPackage">
- <param name="package" type="Qt.Package"/>
- </signal>
- <signal name="rootIndexChanged"/>
- <method name="modelIndex" type="QVariant">
- <param name="idx" type="int"/>
- </method>
- <method name="parentModelIndex" type="QVariant"/>
- </type>
- <type name="Qt.VisualItemModel" version="4.7" defaultProperty="children" extends="QDeclarativeVisualModel">
- <property name="children" type="Qt.Item" isList="true"/>
- <signal name="childrenChanged"/>
- </type>
- <type name="Qt.WorkerScript" version="4.7" extends="Qt.QtObject">
- <property name="source" type="QUrl"/>
- <signal name="sourceChanged"/>
- <signal name="message">
- <param name="messageObject" type="QScriptValue"/>
- </signal>
- <method name="sendMessage">
- <param type="QScriptValue"/>
- </method>
- </type>
- <type name="Qt.XmlListModel" version="4.7" defaultProperty="roles" extends="QListModelInterface">
- <enum name="Status">
- <enumerator name="Null" value="0"/>
- <enumerator name="Ready" value="1"/>
- <enumerator name="Loading" value="2"/>
- <enumerator name="Error" value="3"/>
- </enum>
- <property name="status" type="Status"/>
- <property name="progress" type="qreal"/>
- <property name="source" type="QUrl"/>
- <property name="xml" type="string"/>
- <property name="query" type="string"/>
- <property name="namespaceDeclarations" type="string"/>
- <property name="roles" type="Qt.XmlRole" isList="true"/>
- <property name="count" type="int"/>
- <signal name="statusChanged">
- <param type="QDeclarativeXmlListModel.Status"/>
- </signal>
- <signal name="progressChanged">
- <param name="progress" type="qreal"/>
- </signal>
- <signal name="countChanged"/>
- <signal name="sourceChanged"/>
- <signal name="xmlChanged"/>
- <signal name="queryChanged"/>
- <signal name="namespaceDeclarationsChanged"/>
- <method name="reload"/>
- <method name="get" type="QScriptValue">
- <param name="index" type="int"/>
- </method>
- <method name="errorString" type="string"/>
- </type>
- <type name="Qt.XmlRole" version="4.7" extends="Qt.QtObject">
- <property name="name" type="string"/>
- <property name="query" type="string"/>
- <property name="isKey" type="bool"/>
- <signal name="nameChanged"/>
- <signal name="queryChanged"/>
- <signal name="isKeyChanged"/>
- </type>
- <type name="Qt.labs.folderlistmodel.FolderListModel" version="1.0" extends="QAbstractListModel">
- <enum name="SortField">
- <enumerator name="Unsorted" value="0"/>
- <enumerator name="Name" value="1"/>
- <enumerator name="Time" value="2"/>
- <enumerator name="Size" value="3"/>
- <enumerator name="Type" value="4"/>
- </enum>
- <property name="folder" type="QUrl"/>
- <property name="parentFolder" type="QUrl"/>
- <property name="nameFilters" type="QStringList"/>
- <property name="sortField" type="SortField"/>
- <property name="sortReversed" type="bool"/>
- <property name="showDirs" type="bool"/>
- <property name="showDotAndDotDot" type="bool"/>
- <property name="showOnlyReadable" type="bool"/>
- <property name="count" type="int"/>
- <signal name="folderChanged"/>
- <method name="isFolder" type="bool">
- <param name="index" type="int"/>
- </method>
- </type>
- <type name="Qt.labs.gestures.GestureArea" version="1.0" defaultProperty="data" extends="Qt.Item">
- <property name="gesture" type="QGesture"/>
- </type>
- <type name="Qt.labs.particles.ParticleMotion" version="1.0" extends="Qt.QtObject"/>
- <type name="Qt.labs.particles.ParticleMotionGravity" version="1.0" extends="Qt.labs.particles.ParticleMotion">
- <property name="xattractor" type="qreal"/>
- <property name="yattractor" type="qreal"/>
- <property name="acceleration" type="qreal"/>
- <signal name="xattractorChanged"/>
- <signal name="yattractorChanged"/>
- <signal name="accelerationChanged"/>
- </type>
- <type name="Qt.labs.particles.ParticleMotionLinear" version="1.0" extends="Qt.labs.particles.ParticleMotion"/>
- <type name="Qt.labs.particles.ParticleMotionWander" version="1.0" extends="Qt.labs.particles.ParticleMotion">
- <property name="xvariance" type="qreal"/>
- <property name="yvariance" type="qreal"/>
- <property name="pace" type="qreal"/>
- <signal name="xvarianceChanged"/>
- <signal name="yvarianceChanged"/>
- <signal name="paceChanged"/>
- </type>
- <type name="Qt.labs.particles.Particles" version="1.0" defaultProperty="motion" extends="Qt.Item">
- <property name="source" type="QUrl"/>
- <property name="count" type="int"/>
- <property name="emissionRate" type="int"/>
- <property name="emissionVariance" type="qreal"/>
- <property name="lifeSpan" type="int"/>
- <property name="lifeSpanDeviation" type="int"/>
- <property name="fadeInDuration" type="int"/>
- <property name="fadeOutDuration" type="int"/>
- <property name="angle" type="qreal"/>
- <property name="angleDeviation" type="qreal"/>
- <property name="velocity" type="qreal"/>
- <property name="velocityDeviation" type="qreal"/>
- <property name="motion" type="Qt.labs.particles.ParticleMotion"/>
- <signal name="sourceChanged"/>
- <signal name="countChanged"/>
- <signal name="emissionRateChanged"/>
- <signal name="emissionVarianceChanged"/>
- <signal name="lifeSpanChanged"/>
- <signal name="lifeSpanDeviationChanged"/>
- <signal name="fadeInDurationChanged"/>
- <signal name="fadeOutDurationChanged"/>
- <signal name="angleChanged"/>
- <signal name="angleDeviationChanged"/>
- <signal name="velocityChanged"/>
- <signal name="velocityDeviationChanged"/>
- <signal name="emittingChanged"/>
- <signal name="motionChanged"/>
- <method name="burst">
- <param name="count" type="int"/>
- <param name="emissionRate" type="int"/>
- </method>
- <method name="burst">
- <param name="count" type="int"/>
- </method>
- </type>
- <type name="org.webkit.WebView" version="1.0" defaultProperty="data" extends="Qt.Item">
- <enum name="Status">
- <enumerator name="Null" value="0"/>
- <enumerator name="Ready" value="1"/>
- <enumerator name="Loading" value="2"/>
- <enumerator name="Error" value="3"/>
- </enum>
- <property name="title" type="string"/>
- <property name="icon" type="QPixmap"/>
- <property name="zoomFactor" type="qreal"/>
- <property name="statusText" type="string"/>
- <property name="html" type="string"/>
- <property name="pressGrabTime" type="int"/>
- <property name="preferredWidth" type="int"/>
- <property name="preferredHeight" type="int"/>
- <property name="url" type="QUrl"/>
- <property name="progress" type="qreal"/>
- <property name="status" type="Status"/>
- <property name="reload" type="QAction"/>
- <property name="back" type="QAction"/>
- <property name="forward" type="QAction"/>
- <property name="stop" type="QAction"/>
- <property name="settings" type="QDeclarativeWebSettings"/>
- <property name="javaScriptWindowObjects" type="Qt.QtObject" isList="true"/>
- <property name="newWindowComponent" type="Qt.Component"/>
- <property name="newWindowParent" type="Qt.Item"/>
- <property name="renderingEnabled" type="bool"/>
- <property name="contentsSize" type="QSize"/>
- <property name="contentsScale" type="qreal"/>
- <signal name="preferredWidthChanged"/>
- <signal name="preferredHeightChanged"/>
- <signal name="urlChanged"/>
- <signal name="progressChanged"/>
- <signal name="statusChanged">
- <param type="Status"/>
- </signal>
- <signal name="titleChanged">
- <param type="string"/>
- </signal>
- <signal name="iconChanged"/>
- <signal name="statusTextChanged"/>
- <signal name="htmlChanged"/>
- <signal name="pressGrabTimeChanged"/>
- <signal name="zoomFactorChanged"/>
- <signal name="newWindowComponentChanged"/>
- <signal name="newWindowParentChanged"/>
- <signal name="renderingEnabledChanged"/>
- <signal name="contentsSizeChanged">
- <param type="QSize"/>
- </signal>
- <signal name="contentsScaleChanged"/>
- <signal name="loadStarted"/>
- <signal name="loadFinished"/>
- <signal name="loadFailed"/>
- <signal name="doubleClick">
- <param name="clickX" type="int"/>
- <param name="clickY" type="int"/>
- </signal>
- <signal name="zoomTo">
- <param name="zoom" type="qreal"/>
- <param name="centerX" type="int"/>
- <param name="centerY" type="int"/>
- </signal>
- <signal name="alert">
- <param name="message" type="string"/>
- </signal>
- <method name="evaluateJavaScript" type="QVariant">
- <param type="string"/>
- </method>
- <method name="heuristicZoom" type="bool">
- <param name="clickX" type="int"/>
- <param name="clickY" type="int"/>
- <param name="maxzoom" type="qreal"/>
- </method>
- </type>
- <type name="Script">
- <property name="script" type="string"/>
- <property name="source" type="QUrl"/>
- </type>
-</module>
styles \
gdbmacros \
qmldesigner \
- qml-type-descriptions
+ qml-type-descriptions \
+ generic-highlighter
!isEmpty(copydata) {
--- /dev/null
+<plugin name="%PluginName%" version="0.0.1" compatVersion="0.0.1">
+ <vendor>%VendorName%</vendor>
+ <copyright>%Copyright%</copyright>
+ <license>%License%</license>
+ <description>%Description%</description>
+ <url>%URL%</url>
+ <dependencyList>
+ <dependency name="Core" version="2.1.80"/>
+ </dependencyList>
+</plugin>
--- /dev/null
+#include "%PluginName:l%.%CppHeaderSuffix%"
+
+#include <QtPlugin>
+
+#include <coreplugin/icore.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/actionmanager/command.h>
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/coreconstants.h>
+
+#include <QtPlugin>
+#include <QAction>
+#include <QMessageBox>
+#include <QMainWindow>
+#include <QMenu>
+
+namespace {
+ const char * const ACTION_ID = "%PluginName%.Action";
+ const char * const MENU_ID = "%PluginName%.Menu";
+}
+
+using namespace %PluginName%::Internal;
+
+%PluginName%Impl::%PluginName%Impl()
+{
+ // Create your members
+}
+
+%PluginName%Impl::~%PluginName%Impl()
+{
+ // Unregister objects from the plugin manager's object pool
+ // Delete members
+}
+
+bool %PluginName%Impl::initialize(const QStringList &arguments, QString *errorString)
+{
+ // Register objects in the plugin manager's object pool
+ // Load settings
+ // Add actions to menus
+ // connect to other plugins' signals
+ // "In the initialize method, a plugin can be sure that the plugins it
+ // depends on have initialized their members."
+
+ Q_UNUSED(arguments)
+ Q_UNUSED(errorString)
+ Core::ActionManager *am = Core::ICore::instance()->actionManager();
+
+ QAction *action = new QAction(tr("%PluginName% action"), this);
+ Core::Command *cmd = am->registerAction(action, QLatin1String(ACTION_ID),
+ QList<int>() << Core::Constants::C_GLOBAL_ID);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Meta+A")));
+ connect(action, SIGNAL(triggered()), this, SLOT(triggerAction()));
+
+ Core::ActionContainer *menu = am->createMenu(MENU_ID);
+ menu->menu()->setTitle(tr("%PluginName%"));
+ menu->addAction(cmd);
+ am->actionContainer(Core::Constants::M_TOOLS)->addMenu(menu);
+
+ return true;
+}
+
+void %PluginName%Impl::extensionsInitialized()
+{
+ // Retrieve objects from the plugin manager's object pool
+ // "In the extensionsInitialized method, a plugin can be sure that all
+ // plugins that depend on it are completely initialized."
+}
+
+void %PluginName%Impl::aboutToShutdown()
+{
+ // Save settings
+ // Disconnect from signals that are not needed during shutdown
+}
+
+void %PluginName%Impl::triggerAction()
+{
+ QMessageBox::information(Core::ICore::instance()->mainWindow(),
+ tr("Action triggered"),
+ tr("This is an action from %PluginName%."));
+}
+
+Q_EXPORT_PLUGIN2(%PluginName%, %PluginName%Impl)
--- /dev/null
+#ifndef %PluginName:u%_%CppHeaderSuffix:u%
+#define %PluginName:u%_%CppHeaderSuffix:u%
+
+#include "%PluginName:l%_global.%CppHeaderSuffix%"
+
+#include <extensionsystem/iplugin.h>
+
+namespace %PluginName% {
+namespace Internal {
+
+class %PluginName%Impl : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ %PluginName%Impl();
+ ~%PluginName%Impl();
+
+ bool initialize(const QStringList &arguments, QString *errorString);
+ void extensionsInitialized();
+ void aboutToShutdown();
+
+private slots:
+ void triggerAction();
+};
+
+} // namespace Internal
+} // namespace %PluginName%
+
+#endif // %PluginName:u%_%CppHeaderSuffix:u%
--- /dev/null
+TARGET = %PluginName%
+TEMPLATE = lib
+
+DEFINES += %PluginName:u%_LIBRARY
+
+# %PluginName% files
+
+SOURCES += %PluginName:l%.cpp
+
+HEADERS += %PluginName:l%.h\
+ %PluginName:l%_global.h
+
+OTHER_FILES = %PluginName%.pluginspec
+
+
+# Qt Creator linking
+
+## set the QTC_SOURCE environment variable to override the setting here
+QTCREATOR_SOURCES = $$(QTC_SOURCE)
+isEmpty(QTCREATOR_SOURCES):QTCREATOR_SOURCES=%QtCreatorSources%
+
+## set the QTC_BUILD environment variable to override the setting here
+IDE_BUILD_TREE = $$(QTC_BUILD)
+isEmpty(IDE_BUILD_TREE):IDE_BUILD_TREE=%QtCreatorBuild%
+
+PROVIDER = %VendorName%
+
+include($$QTCREATOR_SOURCES/src/qtcreatorplugin.pri)
+include($$QTCREATOR_SOURCES/src/plugins/coreplugin/coreplugin.pri)
+
+LIBS += -L$$IDE_PLUGIN_PATH/Nokia
--- /dev/null
+#ifndef %PluginName:u%_GLOBAL_%CppHeaderSuffix:u%
+#define %PluginName:u%_GLOBAL_%CppHeaderSuffix:u%
+
+#include <QtCore/qglobal.h>
+
+#if defined(%PluginName:u%_LIBRARY)
+# define %PluginName:u%SHARED_EXPORT Q_DECL_EXPORT
+#else
+# define %PluginName:u%SHARED_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // %PluginName:u%_GLOBAL_H
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+Custom project wizard configuration example file. Note that by convention,
+the project file goes last.
+The "class" and "firstpage" attributes specify that it is a Qt 4 wizard and
+leave room for the Qt 4 target page.
+-->
+<wizard version="1" kind="project"
+ class="qt4project" firstpage="10"
+ id="R.QtCreatorPlugin" category="I.Projects">
+ <icon>qtcreator_logo_24.png</icon>
+ <description>Creates a custom Qt Creator plugin.</description>
+ <displayname>Qt Creator plugin</displayname>;
+ <displaycategory>Other Project</displaycategory>
+ <files>
+ <file source="myplugin.pro" target="%PluginName:l%.pro" openproject="true"/>
+ <file source="MyPlugin.pluginspec" target="%PluginName%.pluginspec" openeditor="true"/>
+ <file source="myplugin.h" target="%PluginName:l%.%CppHeaderSuffix%" openeditor="true"/>
+ <file source="myplugin.cpp" target="%PluginName:l%.%CppSourceSuffix%" openeditor="true"/>
+ <file source="myplugin_global.h" target="%PluginName:l%_global.%CppHeaderSuffix%" openeditor="true"/>
+ </files>
+ <!-- Create a 2nd wizard page with parameters -->
+ <fieldpagetitle>Plugin Information</fieldpagetitle>
+ <fieldpagetitle xml:lang="de">Plugininformationen</fieldpagetitle>
+ <fields>
+ <field mandatory="true" name="PluginName">
+ <fieldcontrol class="QLineEdit" validator="^[a-zA-Z0-9_]+$"
+ defaulttext="MyPlugin" />
+ <fielddescription>Plugin name:</fielddescription>
+ <fielddescription xml:lang="de">Name des Plugins:</fielddescription>
+ </field>
+ <field mandatory="true" name="VendorName">
+ <fieldcontrol class="QLineEdit" validator="^[a-zA-Z0-9_]+$"
+ defaulttext="MyCompany" />
+ <fielddescription>Vendor name:</fielddescription>
+ <fielddescription xml:lang="de">Name des Anbieters:</fielddescription>
+ </field>
+ <field name="Copyright">
+ <fieldcontrol class="QLineEdit"
+ defaulttext="(C) MyCompany" />
+ <fielddescription>Copyright:</fielddescription>
+ <fielddescription xml:lang="de">Copyright:</fielddescription>
+ </field>
+ <field name="License">
+ <fieldcontrol class="QTextEdit"
+ defaulttext="Put your license text here" />
+ <fielddescription>License:</fielddescription>
+ <fielddescription xml:lang="de">Lizenz:</fielddescription>
+ </field>
+ <field name="Description">
+ <fieldcontrol class="QTextEdit"
+ defaulttext="Put a short description of your plugin here"/>
+ <fielddescription>Description:</fielddescription>
+ <fielddescription xml:lang="de">Beschreibung:</fielddescription>
+ </field>
+ <field name="URL">
+ <fieldcontrol class="QLineEdit"
+ defaulttext="http://www.mycompany.com" />
+ <fielddescription>Url:</fielddescription>
+ <fielddescription xml:lang="de">Url:</fielddescription>
+ </field>
+ <field mandatory="true" name="QtCreatorSources">
+ <fieldcontrol class="Utils::PathChooser"
+ defaulttext="" />
+ <fielddescription>Qt Creator sources:</fielddescription>
+ <fielddescription xml:lang="de">Qt Creator Quellen:</fielddescription>
+ </field>
+ <field mandatory="true" name="QtCreatorBuild">
+ <fieldcontrol class="Utils::PathChooser"
+ defaulttext="" />
+ <fielddescription>Qt Creator build:</fielddescription>
+ <fielddescription xml:lang="de">Qt Creator build:</fielddescription>
+ </field>
+ </fields>
+</wizard>
<location line="+1"/>
<source>Creates a Qt application optimized for mobile devices with a Qt Designer-based main window.
-Preselects Qt for Simulator and mobile targets if available</source>
+Preselects Qt for Simulator and mobile targets if available.</source>
<translation>Erstellt eine Qt-Anwendung für mobile Geräte mit einem Qt-Designer-basierten Hauptfenster.
Wählt Qt-Versionen für Simulator und mobile Ziele aus, sofern sie verfügbar sind.</translation>
<key>CFBundleIdentifier</key>
<string>com.nokia.qtcreator</string>
<key>CFBundleVersion</key>
- <string>2.0.80</string>
+ <string>2.1.80</string>
<key>CFBundleShortVersionString</key>
- <string>2.0.80</string>
+ <string>2.1.80</string>
</dict>
</plist>
const u32bit BITMAP_SIZE = Memory_Block::bitmap_size();
const u32bit BLOCK_SIZE = Memory_Block::block_size();
- if(ptr == 0 && n == 0)
+ if(ptr == 0 || n == 0)
return;
Mutex_Holder lock(mutex);
#include <botan/x509_key.h>
#include <botan/pubkey_enums.h>
#include <botan/cvc_gen_cert.h>
-#include <botan/cvc_req.h>
namespace Botan {
if(hash_id == 0)
{
+ std::string hashname = hash->name();
delete hash;
- throw Encoding_Error("EMSA2 cannot be used with " + hash->name());
+ throw Encoding_Error("EMSA2 cannot be used with " + hashname);
}
}
!cipher->valid_keylength(OUTPUT_LENGTH) ||
!mac->valid_keylength(OUTPUT_LENGTH))
{
+ std::string ciphername = cipher->name(), macname = mac->name();
delete cipher;
delete mac;
throw Internal_Error("Randpool: Invalid algorithm combination " +
- cipher->name() + "/" + mac->name());
+ ciphername + "/" + macname);
}
buffer.create(BLOCK_SIZE);
result = verifier->verify_message (H, sigData);
delete verifier;
if (dsaKey) delete dsaKey;
- if (rsaKey) delete dsaKey;
+ if (rsaKey) delete rsaKey;
if (!result)
{
return 0;
}
-int ne7ssh::connectWithPassword (const char *host, const int port, const char* username, const char* password, bool shell, const int timeout)
+int ne7ssh::connectWithPassword (const char *host, const int port,
+ const char* username, const char* password, bool shell, const int timeout,
+ void (*callbackFunc)(void *), void *callbackArg)
{
int channel;
uint32 currentRecord, z;
uint32 channelID;
- ne7ssh_connection* con = new ne7ssh_connection ();
+ ne7ssh_connection* con = new ne7ssh_connection (callbackFunc, callbackArg);
if (!lock()) return -1;
if (!conCount) connections = (ne7ssh_connection**) malloc (sizeof (ne7ssh_connection*));
return channel;
}
-int ne7ssh::connectWithKey (const char* host, const int port, const char* username, const char* privKeyFileName, bool shell, const int timeout)
+int ne7ssh::connectWithKey (const char* host, const int port,
+ const char* username, const char* privKeyFileName, bool shell,
+ const int timeout, void (*callbackFunc)(void *), void *callbackArg)
{
int channel;
uint32 currentRecord, z;
uint32 channelID;
- ne7ssh_connection* con = new ne7ssh_connection ();
+ ne7ssh_connection* con = new ne7ssh_connection (callbackFunc, callbackArg);
if (!lock()) return -1;
if (!conCount) connections = (ne7ssh_connection**) malloc (sizeof (ne7ssh_connection*) * (conCount + 1));
else connections = (ne7ssh_connection**) realloc (connections, sizeof (ne7ssh_connection*) * (conCount + 1));
data = connections[i]->getReceived();
if (data.size())
{
- buffer = alloc(connections[i]->getReceived().size());
- strcpy(buffer, reinterpret_cast<char*>(connections[i]->getReceived().begin()));
+ Botan::SecureVector<Botan::byte>& received=connections[i]->getReceived();
+ buffer = alloc(received.size());
+ strncpy(buffer, reinterpret_cast<char*>(received.begin()), received.size());
connections[i]->resetReceiveBuffer();
}
break;
* @param timeout Timeout for the connection procedure, in seconds.
* @return Returns newly assigned channel ID, or -1 if connection failed.
*/
- int connectWithPassword (const char* host, const int port, const char* username, const char* password, bool shell = true, const int timeout = 0);
+ int connectWithPassword (const char* host, const int port, const char* username,
+ const char* password, bool shell = true, const int timeout = 0,
+ void (*callbackFunc)(void *) = 0, void *callbackArg = 0);
/**
* Connect to remote host using SSH2 protocol, with publickey authentication.
* @param timeout Timeout for the connection procedure, in seconds.
* @return Returns newly assigned channel ID, or -1 if connection failed.
*/
- int connectWithKey (const char* host, const int port, const char* username, const char* privKeyFileName, bool shell = true, const int timeout = 0);
+ int connectWithKey (const char* host, const int port, const char* username,
+ const char* privKeyFileName, bool shell = true, const int timeout = 0,
+ void (*callbackFunc)(void *) = 0, void *callbackArg = 0);
/**
* Retrieves a pointer to all current connections.
using namespace Botan;
-ne7ssh_connection::ne7ssh_connection() : sock (-1), thisChannel(0), sftp(0), connected(false), cmdRunning(false), cmdClosed(false)
+ne7ssh_connection::ne7ssh_connection(void (*callbackFunc)(void *),
+ void *callbackArg)
+ : sock (-1), thisChannel(0), sftp(0), connected(false), cmdRunning(false),
+ cmdClosed(false), callbackFunc(callbackFunc), callbackArg(callbackArg)
{
session = new ne7ssh_session();
crypto = new ne7ssh_crypt(session);
void ne7ssh_connection::handleData ()
{
channel->receive();
+ if (callbackFunc && getReceived().size() > 0)
+ callbackFunc(callbackArg);
}
void ne7ssh_connection::sendData (const char* data)
bool cmdRunning;
bool cmdClosed;
+ void (*callbackFunc)(void *);
+ void *callbackArg;
/**
* Checks if remote side is returning a correctly formated SSH version string, and makes sure that version 2 of SSH protocol is supported by the remote side.
/**
* ne7ssh_connection class constructor.
*/
- ne7ssh_connection();
+ ne7ssh_connection(void (*callbackFunc)(void *) = 0, void *callbackArg = 0);
/**
* ne7ssh_connection class destructor.
fseek (FI, 0L, SEEK_END);
size = ftell (FI);
- rewind (FI);
-
- data = (Botan::byte*) malloc (size);
- fread (data, size, 1, FI);
- fclose (FI);
- buffer.append (data, (u32bit) size);
- free (data);
- return true;
+ if(size > 0) {
+ rewind (FI);
+
+ data = (Botan::byte*) malloc (size);
+ fread (data, size, 1, FI);
+ fclose (FI);
+ buffer.append (data, (u32bit) size);
+ free (data);
+ return true;
+ }
+ fclose(FI);
+ return false;
}
void ne7ssh_string::addBigInt (const Botan::BigInt& bn)
}*/
}
- if (rSeq == MAX_SEQUENCE) seq = 0;
+ if (rSeq == MAX_SEQUENCE) rSeq = 0;
else rSeq++;
_cmd = *(decrypted.begin() + 5);
**
**************************************************************************/
-#ifndef ASTPARENT_H
-#define ASTPARENT_H
+#ifndef CPLUSPLUS_ASTPARENT_H
+#define CPLUSPLUS_ASTPARENT_H
#include <ASTVisitor.h>
#include <QtCore/QHash>
} // namespace CPlusPlus
-#endif // ASTPARENT_H
+#endif // CPLUSPLUS_ASTPARENT_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "ASTPath.h"
+
+#include <AST.h>
+#include <TranslationUnit.h>
+
+#ifdef DEBUG_AST_PATH
+# include <QtCore/QDebug>
+# include <typeinfo>
+#endif // DEBUG_AST_PATH
+
+using namespace CPlusPlus;
+
+QList<AST *> ASTPath::operator()(int line, int column)
+{
+ _nodes.clear();
+ _line = line + 1;
+ _column = column + 1;
+ accept(_doc->translationUnit()->ast());
+ return _nodes;
+}
+
+#ifdef DEBUG_AST_PATH
+void ASTPath::dump(const QList<AST *> nodes)
+{
+ qDebug() << "ASTPath dump," << nodes.size() << "nodes:";
+ for (int i = 0; i < nodes.size(); ++i)
+ qDebug() << qPrintable(QString(i + 1, QLatin1Char('-'))) << typeid(*nodes.at(i)).name();
+}
+#endif // DEBUG_AST_PATH
+
+bool ASTPath::preVisit(AST *ast)
+{
+ unsigned firstToken = ast->firstToken();
+ unsigned lastToken = ast->lastToken();
+
+ if (firstToken > 0 && lastToken > firstToken) {
+ unsigned startLine, startColumn;
+ getTokenStartPosition(firstToken, &startLine, &startColumn);
+
+ if (_line > startLine || (_line == startLine && _column >= startColumn)) {
+
+ unsigned endLine, endColumn;
+ getTokenEndPosition(lastToken - 1, &endLine, &endColumn);
+
+ if (_line < endLine || (_line == endLine && _column <= endColumn)) {
+ _nodes.append(ast);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef CPLUSPLUS_ASTPATH_H
+#define CPLUSPLUS_ASTPATH_H
+
+#include <ASTfwd.h>
+#include <ASTVisitor.h>
+
+#include "CppDocument.h"
+
+#include <QtCore/QList>
+#include <QtGui/QTextCursor>
+
+#undef DEBUG_AST_PATH
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT ASTPath: public ASTVisitor
+{
+public:
+ ASTPath(Document::Ptr doc)
+ : ASTVisitor(doc->translationUnit()),
+ _doc(doc), _line(0), _column(0)
+ {}
+
+ QList<AST *> operator()(const QTextCursor &cursor)
+ { return this->operator()(cursor.blockNumber(), cursor.columnNumber()); }
+
+ /// line and column are 0-based!
+ QList<AST *> operator()(int line, int column);
+
+#ifdef DEBUG_AST_PATH
+ static void dump(const QList<AST *> nodes);
+#endif
+
+protected:
+ virtual bool preVisit(AST *ast);
+
+private:
+ Document::Ptr _doc;
+ unsigned _line;
+ unsigned _column;
+ QList<AST *> _nodes;
+};
+
+} // namespace CppTools
+
+#endif // CPLUSPLUS_ASTPATH_H
**
**************************************************************************/
#include "BackwardsScanner.h"
+#include "TokenCache.h"
#include <Token.h>
#include <QtGui/QTextCursor>
+#include <QTextDocument>
using namespace CPlusPlus;
-BackwardsScanner::BackwardsScanner(const QTextCursor &cursor, const QString &suffix, int maxBlockCount)
- : _offset(0)
+BackwardsScanner::BackwardsScanner(TokenCache *tokenCache, const QTextCursor &cursor, int maxBlockCount, const QString &suffix)
+ : _tokenCache(tokenCache)
+ , _offset(0)
, _blocksTokenized(0)
, _block(cursor.block())
, _maxBlockCount(maxBlockCount)
{
- _tokenize.setQtMocRunEnabled(true);
- _tokenize.setSkipComments(true);
- _tokenize.setObjCEnabled(true);
- _text = _block.text().left(cursor.position() - cursor.block().position());
+ int pos = cursor.position() - cursor.block().position();
+ _text = _block.text().left(pos);
+ _text += suffix;
- if (! suffix.isEmpty())
- _text += suffix;
+ _tokens.append(tokenCache->tokensForBlock(_block));
- _tokens.append(_tokenize(_text, previousBlockState(_block)));
+ for (int i = _tokens.size() - 1; i >= 0; --i) {
+ const int tokenEnd = _tokens.at(i).end();
+
+ if ((tokenEnd < pos) ||
+ (tokenEnd == pos && suffix.isEmpty())) {
+ break;
+ } else {
+ _tokens.removeAt(i);
+ }
+ }
+
+ QString remainingText;
+ if (!_tokens.isEmpty())
+ remainingText = _text.mid(_tokens.last().end());
+ if (!remainingText.isEmpty()) {
+ SimpleLexer tokenize;
+ tokenize.setQtMocRunEnabled(true);
+ tokenize.setSkipComments(true);
+ tokenize.setObjCEnabled(true);
+
+ _tokens.append(tokenize(remainingText, TokenCache::previousBlockState(_block)));
+ }
_startToken = _tokens.size();
}
-int BackwardsScanner::state() const
-{ return _tokenize.state(); }
-
SimpleToken BackwardsScanner::LA(int index) const
{ return const_cast<BackwardsScanner *>(this)->fetchToken(_startToken - index); }
SimpleToken BackwardsScanner::operator[](int index) const
{ return const_cast<BackwardsScanner *>(this)->fetchToken(index); }
-const SimpleToken &BackwardsScanner::fetchToken(int i)
+const SimpleToken &BackwardsScanner::fetchToken(int tokenIndex)
{
- while (_offset + i < 0) {
+ while (_offset + tokenIndex < 0) {
_block = _block.previous();
if (_blocksTokenized == _maxBlockCount || !_block.isValid()) {
++_offset;
} else {
++_blocksTokenized;
+ QList<SimpleToken> newTokens = _tokenCache->tokensForBlock(_block);
QString blockText = _block.text();
_text.prepend(QLatin1Char('\n'));
_text.prepend(blockText);
for (int i = 0; i < _tokens.size(); ++i) {
SimpleToken t = _tokens.at(i);
t.setPosition(t.position() + blockText.length() + 1);
- t.setText(_text.midRef(t.position(), t.length()));
adaptedTokens.append(t);
}
- _tokens = _tokenize(blockText, previousBlockState(_block));
- _offset += _tokens.size();
+ _tokens = newTokens;
+ _offset += newTokens.size();
_tokens += adaptedTokens;
}
}
- return _tokens.at(_offset + i);
+ return _tokens.at(_offset + tokenIndex);
}
int BackwardsScanner::startToken() const
return _text.midRef(firstToken.begin(), firstToken.length());
}
-int BackwardsScanner::previousBlockState(const QTextBlock &block)
-{
- const QTextBlock prevBlock = block.previous();
-
- if (prevBlock.isValid()) {
- int state = prevBlock.userState();
-
- if (state != -1)
- return state;
- }
-
- return 0;
-}
-
int BackwardsScanner::size() const
{
return _tokens.size();
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
-#ifndef BACKWARDSSCANNER_H
-#define BACKWARDSSCANNER_H
+#ifndef CPLUSPLUS_BACKWARDSSCANNER_H
+#define CPLUSPLUS_BACKWARDSSCANNER_H
#include "SimpleLexer.h"
namespace CPlusPlus {
+class TokenCache;
+
class CPLUSPLUS_EXPORT BackwardsScanner
{
enum { MAX_BLOCK_COUNT = 10 };
public:
- BackwardsScanner(const QTextCursor &cursor,
- const QString &suffix = QString(),
- int maxBlockCount = MAX_BLOCK_COUNT);
+ BackwardsScanner(TokenCache *cache,
+ const QTextCursor &cursor,
+ int maxBlockCount = MAX_BLOCK_COUNT,
+ const QString &suffix = QString());
- int state() const;
int startToken() const;
int startPosition() const;
int startOfMatchingBrace(int index) const;
int startOfBlock(int index) const;
- static int previousBlockState(const QTextBlock &block);
-
int size() const;
private:
- const SimpleToken &fetchToken(int i);
+ const SimpleToken &fetchToken(int tokenIndex);
private:
+ TokenCache *_tokenCache;
QList<SimpleToken> _tokens;
int _offset;
int _blocksTokenized;
QTextBlock _block;
QString _text;
- SimpleLexer _tokenize;
int _maxBlockCount;
int _startToken;
};
} // end of namespace CPlusPlus
-#endif // BACKWARDSSCANNER_H
+#endif // CPLUSPLUS_BACKWARDSSCANNER_H
#include <TranslationUnit.h>
#include <Scope.h>
#include <AST.h>
+#include <SymbolVisitor.h>
-using namespace CPlusPlus;
-
+#include <QCoreApplication>
+#include <QDebug>
-CheckUndefinedSymbols::CheckUndefinedSymbols(Document::Ptr doc)
- : ASTVisitor(doc->translationUnit()), _doc(doc)
-{ }
+using namespace CPlusPlus;
-CheckUndefinedSymbols::~CheckUndefinedSymbols()
-{ }
+namespace {
-void CheckUndefinedSymbols::setGlobalNamespaceBinding(NamespaceBindingPtr globalNamespaceBinding)
+class CollectTypes: protected SymbolVisitor
{
- _globalNamespaceBinding = globalNamespaceBinding;
- _types.clear();
- _protocols.clear();
+ Document::Ptr _doc;
+ Snapshot _snapshot;
+ QSet<QByteArray> _types;
+ QList<ScopedSymbol *> _scopes;
+ QList<NameAST *> _names;
+ bool _mainDocument;
- if (_globalNamespaceBinding) {
- QSet<NamespaceBinding *> processed;
- buildTypeMap(_globalNamespaceBinding.data(), &processed);
+public:
+ CollectTypes(Document::Ptr doc, const Snapshot &snapshot)
+ : _doc(doc), _snapshot(snapshot), _mainDocument(false)
+ {
+ QSet<Namespace *> processed;
+ process(doc, &processed);
}
-}
-void CheckUndefinedSymbols::operator()(AST *ast)
-{ accept(ast); }
+ const QSet<QByteArray> &types() const
+ {
+ return _types;
+ }
-QByteArray CheckUndefinedSymbols::templateParameterName(NameAST *ast) const
-{
- if (ast && ast->name) {
- if (const Identifier *id = ast->name->identifier())
- return QByteArray::fromRawData(id->chars(), id->size());
+ const QList<ScopedSymbol *> &scopes() const
+ {
+ return _scopes;
}
- return QByteArray();
-}
+ static Scope *findScope(unsigned tokenOffset, const QList<ScopedSymbol *> &scopes)
+ {
+ for (int i = scopes.size() - 1; i != -1; --i) {
+ ScopedSymbol *symbol = scopes.at(i);
+ const unsigned start = symbol->startOffset();
+ const unsigned end = symbol->endOffset();
-QByteArray CheckUndefinedSymbols::templateParameterName(DeclarationAST *ast) const
-{
- if (ast) {
- if (TypenameTypeParameterAST *d = ast->asTypenameTypeParameter())
- return templateParameterName(d->name);
- else if (TemplateTypeParameterAST *d = ast->asTemplateTypeParameter())
- return templateParameterName(d->name);
- else if (ParameterDeclarationAST *d = ast->asParameterDeclaration()) {
- if (d->symbol) {
- if (const Identifier *id = d->symbol->identifier())
- return QByteArray::fromRawData(id->chars(), id->size());
- }
+ if (tokenOffset >= start && tokenOffset < end)
+ return symbol->members();
}
+
+ return 0;
}
- return QByteArray();
-}
-bool CheckUndefinedSymbols::isType(const QByteArray &name) const
-{
- for (int i = _compoundStatementStack.size() - 1; i != -1; --i) {
- Scope *members = _compoundStatementStack.at(i)->symbol->members();
+protected:
+ void process(Document::Ptr doc, QSet<Namespace *> *processed)
+ {
+ if (! doc)
+ return;
+ else if (! processed->contains(doc->globalNamespace())) {
+ processed->insert(doc->globalNamespace());
- for (unsigned m = 0; m < members->symbolCount(); ++m) {
- Symbol *member = members->symbolAt(m);
+ foreach (const Document::Include &i, doc->includes())
+ process(_snapshot.document(i.fileName()), processed);
- if (member->isTypedef() && member->isDeclaration()) {
- if (const Identifier *id = member->identifier()) {
- if (name == id->chars())
- return true;
- }
- }
+ _mainDocument = (doc == _doc); // ### improve
+ accept(doc->globalNamespace());
}
}
- for (int i = _templateDeclarationStack.size() - 1; i != - 1; --i) {
- TemplateDeclarationAST *templateDeclaration = _templateDeclarationStack.at(i);
+ void addType(const Identifier *id)
+ {
+ if (id)
+ _types.insert(QByteArray::fromRawData(id->chars(), id->size()));
+ }
+
+ void addType(const Name *name)
+ {
+ if (! name) {
+ return;
+
+ } else if (const QualifiedNameId *q = name->asQualifiedNameId()) {
+ for (unsigned i = 0; i < q->nameCount(); ++i)
+ addType(q->nameAt(i));
- for (DeclarationListAST *it = templateDeclaration->template_parameter_list; it; it = it->next) {
- DeclarationAST *templateParameter = it->value;
+ } else if (name->isNameId() || name->isTemplateNameId()) {
+ addType(name->identifier());
- if (templateParameterName(templateParameter) == name)
- return true;
}
}
- return _types.contains(name);
-}
+ void addScope(ScopedSymbol *symbol)
+ {
+ if (_mainDocument)
+ _scopes.append(symbol);
+ }
-bool CheckUndefinedSymbols::isType(const Identifier *id) const
-{
- if (! id)
- return false;
+ // nothing to do
+ virtual bool visit(UsingNamespaceDirective *) { return true; }
+ virtual bool visit(UsingDeclaration *) { return true; }
+ virtual bool visit(Argument *) { return true; }
+ virtual bool visit(BaseClass *) { return true; }
+
+ virtual bool visit(Function *symbol)
+ {
+ for (TemplateParameters *p = symbol->templateParameters(); p; p = p->previous()) {
+ Scope *scope = p->scope();
+ for (unsigned i = 0; i < scope->symbolCount(); ++i)
+ accept(scope->symbolAt(i));
+ }
- return isType(QByteArray::fromRawData(id->chars(), id->size()));
-}
+ addScope(symbol);
+ return true;
+ }
-void CheckUndefinedSymbols::addType(const Name *name)
-{
- if (! name)
- return;
+ virtual bool visit(Block *symbol)
+ {
+ addScope(symbol);
+ return true;
+ }
- if (const Identifier *id = name->identifier())
- _types.insert(QByteArray(id->chars(), id->size()));
-}
+ virtual bool visit(NamespaceAlias *symbol)
+ {
+ addType(symbol->name());
+ return true;
+ }
-void CheckUndefinedSymbols::addProtocol(const Name *name)
-{
- if (!name)
- return;
+ virtual bool visit(Declaration *symbol)
+ {
+ if (symbol->isTypedef())
+ addType(symbol->name());
- if (const Identifier *id = name->identifier())
- _protocols.insert(QByteArray(id->chars(), id->size()));
-}
+ return true;
+ }
-bool CheckUndefinedSymbols::isProtocol(const QByteArray &name) const
-{
- return _protocols.contains(name);
-}
+ virtual bool visit(TypenameArgument *symbol)
+ {
+ addType(symbol->name());
+ return true;
+ }
-void CheckUndefinedSymbols::buildTypeMap(Class *klass)
-{
- addType(klass->name());
+ virtual bool visit(Enum *symbol)
+ {
+ addScope(symbol);
+ addType(symbol->name());
+ return true;
+ }
- for (unsigned i = 0; i < klass->memberCount(); ++i) {
- buildMemberTypeMap(klass->memberAt(i));
+ virtual bool visit(Namespace *symbol)
+ {
+ addScope(symbol);
+ addType(symbol->name());
+ return true;
}
-}
-void CheckUndefinedSymbols::buildMemberTypeMap(Symbol *member)
-{
- if (member == 0)
- return;
+ virtual bool visit(Class *symbol)
+ {
+ for (TemplateParameters *p = symbol->templateParameters(); p; p = p->previous()) {
+ Scope *scope = p->scope();
+ for (unsigned i = 0; i < scope->symbolCount(); ++i)
+ accept(scope->symbolAt(i));
+ }
- if (Class *klass = member->asClass()) {
- buildTypeMap(klass);
- } else if (Enum *e = member->asEnum()) {
- addType(e->name());
- } else if (ForwardClassDeclaration *fwd = member->asForwardClassDeclaration()) {
- addType(fwd->name());
- } else if (Declaration *decl = member->asDeclaration()) {
- if (decl->isTypedef())
- addType(decl->name());
+ addScope(symbol);
+ addType(symbol->name());
+ return true;
}
-}
-void CheckUndefinedSymbols::buildTypeMap(NamespaceBinding *binding, QSet<NamespaceBinding *> *processed)
-{
- if (! processed->contains(binding)) {
- processed->insert(binding);
-
- if (const Identifier *id = binding->identifier()) {
- _namespaceNames.insert(QByteArray(id->chars(), id->size()));
+ virtual bool visit(ForwardClassDeclaration *symbol)
+ {
+ for (TemplateParameters *p = symbol->templateParameters(); p; p = p->previous()) {
+ Scope *scope = p->scope();
+ for (unsigned i = 0; i < scope->symbolCount(); ++i)
+ accept(scope->symbolAt(i));
}
- foreach (Namespace *ns, binding->symbols) {
- for (unsigned i = 0; i < ns->memberCount(); ++i) {
- Symbol *member = ns->memberAt(i);
-
- if (Class *klass = member->asClass()) {
- buildTypeMap(klass);
- } else if (Enum *e = member->asEnum()) {
- addType(e->name());
- } else if (ForwardClassDeclaration *fwd = member->asForwardClassDeclaration()) {
- addType(fwd->name());
- } else if (Declaration *decl = member->asDeclaration()) {
- if (decl->isTypedef())
- addType(decl->name());
- } else if (ObjCForwardClassDeclaration *fKlass = member->asObjCForwardClassDeclaration()) {
- addType(fKlass->name());
- } else if (ObjCClass *klass = member->asObjCClass()) {
- addType(klass->name());
-
- for (unsigned i = 0; i < klass->memberCount(); ++i)
- buildMemberTypeMap(klass->memberAt(i));
- } else if (ObjCForwardProtocolDeclaration *fProto = member->asObjCForwardProtocolDeclaration()) {
- addProtocol(fProto->name());
- } else if (ObjCProtocol *proto = member->asObjCProtocol()) {
- addProtocol(proto->name());
-
- for (unsigned i = 0; i < proto->memberCount(); ++i)
- buildMemberTypeMap(proto->memberAt(i));
- }
- }
- }
+ addType(symbol->name());
+ return true;
+ }
- foreach (NamespaceBinding *childBinding, binding->children) {
- buildTypeMap(childBinding, processed);
- }
+ // Objective-C
+ virtual bool visit(ObjCBaseClass *) { return true; }
+ virtual bool visit(ObjCBaseProtocol *) { return true; }
+ virtual bool visit(ObjCPropertyDeclaration *) { return true; }
+
+ virtual bool visit(ObjCMethod *symbol)
+ {
+ addScope(symbol);
+ return true;
}
-}
-FunctionDeclaratorAST *CheckUndefinedSymbols::currentFunctionDeclarator() const
-{
- if (_functionDeclaratorStack.isEmpty())
- return 0;
+ virtual bool visit(ObjCClass *symbol)
+ {
+ addScope(symbol);
+ addType(symbol->name());
+ return true;
+ }
- return _functionDeclaratorStack.last();
-}
+ virtual bool visit(ObjCForwardClassDeclaration *symbol)
+ {
+ addType(symbol->name());
+ return true;
+ }
-CompoundStatementAST *CheckUndefinedSymbols::compoundStatement() const
-{
- if (_compoundStatementStack.isEmpty())
- return 0;
+ virtual bool visit(ObjCProtocol *symbol)
+ {
+ addScope(symbol);
+ addType(symbol->name());
+ return true;
+ }
- return _compoundStatementStack.last();
-}
+ virtual bool visit(ObjCForwardProtocolDeclaration *symbol)
+ {
+ addType(symbol->name());
+ return true;
+ }
+};
-bool CheckUndefinedSymbols::visit(FunctionDeclaratorAST *ast)
+} // end of anonymous namespace
+
+CheckUndefinedSymbols::CheckUndefinedSymbols(TranslationUnit *unit, const LookupContext &context)
+ : ASTVisitor(unit), _context(context)
{
- _functionDeclaratorStack.append(ast);
- return true;
+ _fileName = context.thisDocument()->fileName();
+ CollectTypes collectTypes(context.thisDocument(), context.snapshot());
+ _potentialTypes = collectTypes.types();
+ _scopes = collectTypes.scopes();
}
-void CheckUndefinedSymbols::endVisit(FunctionDeclaratorAST *)
+CheckUndefinedSymbols::~CheckUndefinedSymbols()
+{ }
+
+QList<Document::DiagnosticMessage> CheckUndefinedSymbols::operator()(AST *ast)
{
- _functionDeclaratorStack.removeLast();
+ _diagnosticMessages.clear();
+ accept(ast);
+ return _diagnosticMessages;
}
-bool CheckUndefinedSymbols::visit(TypeofSpecifierAST *)
+bool CheckUndefinedSymbols::warning(unsigned line, unsigned column, const QString &text, unsigned length)
{
+ Document::DiagnosticMessage m(Document::DiagnosticMessage::Warning, _fileName, line, column, text, length);
+ _diagnosticMessages.append(m);
return false;
}
-bool CheckUndefinedSymbols::visit(NamedTypeSpecifierAST *ast)
+bool CheckUndefinedSymbols::warning(AST *ast, const QString &text)
{
- if (ast->name) {
- if (! ast->name->name) {
- unsigned line, col;
- getTokenStartPosition(ast->firstToken(), &line, &col);
- // qWarning() << _doc->fileName() << line << col;
- } else if (const Identifier *id = ast->name->name->identifier()) {
- if (! isType(id)) {
- if (FunctionDeclaratorAST *functionDeclarator = currentFunctionDeclarator()) {
- if (functionDeclarator->as_cpp_initializer)
- return true;
- }
+ const Token &firstToken = tokenAt(ast->firstToken());
+ const Token &lastToken = tokenAt(ast->lastToken() - 1);
- Overview oo;
- translationUnit()->warning(ast->firstToken(), "`%s' is not a type name",
- qPrintable(oo(ast->name->name)));
- }
+ const unsigned length = lastToken.end() - firstToken.begin();
+ unsigned line = 1, column = 1;
+ getTokenStartPosition(ast->firstToken(), &line, &column);
+
+ warning(line, column, text, length);
+ return false;
+}
+
+bool CheckUndefinedSymbols::visit(NamespaceAST *ast)
+{
+ if (ast->identifier_token) {
+ const Token &tok = tokenAt(ast->identifier_token);
+ if (! tok.generated()) {
+ unsigned line, column;
+ getTokenStartPosition(ast->identifier_token, &line, &column);
+ Use use(line, column, tok.length());
+ _typeUsages.append(use);
}
}
+
return true;
}
-bool CheckUndefinedSymbols::visit(TemplateDeclarationAST *ast)
+bool CheckUndefinedSymbols::visit(UsingDirectiveAST *)
{
- _templateDeclarationStack.append(ast);
return true;
}
-void CheckUndefinedSymbols::endVisit(TemplateDeclarationAST *)
+bool CheckUndefinedSymbols::visit(SimpleDeclarationAST *)
{
- _templateDeclarationStack.removeLast();
+ return true;
}
-bool CheckUndefinedSymbols::visit(ClassSpecifierAST *ast)
+bool CheckUndefinedSymbols::visit(NamedTypeSpecifierAST *)
{
- bool hasQ_OBJECT_CHECK = false;
-
- if (ast->symbol) {
- Class *klass = ast->symbol->asClass();
+ return true;
+}
- for (unsigned i = 0; i < klass->memberCount(); ++i) {
- Symbol *symbol = klass->memberAt(i);
+void CheckUndefinedSymbols::checkNamespace(NameAST *name)
+{
+ if (! name)
+ return;
- if (symbol->name() && symbol->name()->isNameId()) {
- const NameId *nameId = symbol->name()->asNameId();
+ unsigned line, column;
+ getTokenStartPosition(name->firstToken(), &line, &column);
- if (! qstrcmp(nameId->identifier()->chars(), "qt_check_for_QOBJECT_macro")) {
- hasQ_OBJECT_CHECK = true;
- break;
- }
- }
+ Scope *enclosingScope = _context.thisDocument()->scopeAt(line, column);
+ if (ClassOrNamespace *b = _context.lookupType(name->name, enclosingScope)) {
+ foreach (Symbol *s, b->symbols()) {
+ if (s->isNamespace())
+ return;
}
}
- _qobjectStack.append(hasQ_OBJECT_CHECK);
-
- return true;
+ const unsigned length = tokenAt(name->lastToken() - 1).end() - tokenAt(name->firstToken()).begin();
+ warning(line, column, QCoreApplication::translate("CheckUndefinedSymbols", "Expected a namespace-name"), length);
}
-void CheckUndefinedSymbols::endVisit(ClassSpecifierAST *)
-{ _qobjectStack.removeLast(); }
-
-bool CheckUndefinedSymbols::qobjectCheck() const
+void CheckUndefinedSymbols::checkName(NameAST *ast)
{
- if (_qobjectStack.isEmpty())
- return false;
-
- return _qobjectStack.last();
-}
-
-bool CheckUndefinedSymbols::visit(FunctionDefinitionAST *ast)
-{
- if (ast->symbol) {
- Function *fun = ast->symbol->asFunction();
- if ((fun->isSignal() || fun->isSlot()) && ! qobjectCheck()) {
- translationUnit()->warning(ast->firstToken(),
- "you forgot the Q_OBJECT macro");
+ if (ast->name) {
+ if (const Identifier *ident = ast->name->identifier()) {
+ const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
+ if (_potentialTypes.contains(id)) {
+ Scope *scope = findScope(ast);
+ const QList<Symbol *> candidates = _context.lookup(ast->name, scope);
+ addTypeUsage(candidates, ast);
+ }
}
}
- return true;
}
-void CheckUndefinedSymbols::endVisit(FunctionDefinitionAST *)
-{ }
-
-bool CheckUndefinedSymbols::visit(CompoundStatementAST *ast)
+bool CheckUndefinedSymbols::visit(SimpleNameAST *ast)
{
- _compoundStatementStack.append(ast);
+ checkName(ast);
return true;
}
-void CheckUndefinedSymbols::endVisit(CompoundStatementAST *)
+bool CheckUndefinedSymbols::visit(TemplateIdAST *ast)
{
- _compoundStatementStack.removeLast();
+ checkName(ast);
+ return true;
}
-bool CheckUndefinedSymbols::visit(SimpleDeclarationAST *ast)
+bool CheckUndefinedSymbols::visit(DestructorNameAST *ast)
{
- const bool check = qobjectCheck();
- for (List<Declaration *> *it = ast->symbols; it; it = it->next) {
- Declaration *decl = it->value;
-
- if (Function *fun = decl->type()->asFunctionType()) {
- if ((fun->isSignal() || fun->isSlot()) && ! check) {
- translationUnit()->warning(ast->firstToken(),
- "you forgot the Q_OBJECT macro");
- }
- }
- }
+ checkName(ast);
return true;
}
-bool CheckUndefinedSymbols::visit(BaseSpecifierAST *base)
+bool CheckUndefinedSymbols::visit(QualifiedNameAST *ast)
{
- if (NameAST *nameAST = base->name) {
- bool resolvedBaseClassName = false;
-
- if (const Name *name = nameAST->name) {
- const Identifier *id = name->identifier();
- const QByteArray spell = QByteArray::fromRawData(id->chars(), id->size());
- if (isType(spell))
- resolvedBaseClassName = true;
- }
+ if (ast->name) {
+ Scope *scope = findScope(ast);
- if (! resolvedBaseClassName)
- translationUnit()->warning(nameAST->firstToken(), "expected class-name");
- }
+ ClassOrNamespace *b = 0;
+ if (NestedNameSpecifierListAST *it = ast->nested_name_specifier_list) {
+ NestedNameSpecifierAST *nested_name_specifier = it->value;
+ if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) { // ### remove shadowing
- return true;
-}
+ if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId())
+ accept(template_id->template_argument_list);
-bool CheckUndefinedSymbols::visit(UsingDirectiveAST *ast)
-{
- if (ast->symbol && ast->symbol->name() && _globalNamespaceBinding) {
- const Location loc = Location(ast->symbol);
+ const Name *name = class_or_namespace_name->name;
+ b = _context.lookupType(name, scope);
+ addTypeUsage(b, class_or_namespace_name);
- NamespaceBinding *binding = _globalNamespaceBinding.data();
+ for (it = it->next; b && it; it = it->next) {
+ NestedNameSpecifierAST *nested_name_specifier = it->value;
- if (Scope *enclosingNamespaceScope = ast->symbol->enclosingNamespaceScope())
- binding = NamespaceBinding::find(enclosingNamespaceScope->owner()->asNamespace(), binding);
+ if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) {
+ if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId())
+ accept(template_id->template_argument_list);
- if (! binding || ! binding->resolveNamespace(loc, ast->symbol->name())) {
- translationUnit()->warning(ast->name->firstToken(),
- "expected a namespace");
+ b = b->findType(class_or_namespace_name->name);
+ addTypeUsage(b, class_or_namespace_name);
+ }
+ }
+ }
}
+
+ if (b && ast->unqualified_name)
+ addTypeUsage(b->find(ast->unqualified_name->name), ast->unqualified_name);
}
- return true;
+ return false;
}
-bool CheckUndefinedSymbols::visit(QualifiedNameAST *ast)
+bool CheckUndefinedSymbols::visit(TypenameTypeParameterAST *ast)
{
- if (ast->name) {
- const QualifiedNameId *q = ast->name->asQualifiedNameId();
- for (unsigned i = 0; i < q->nameCount() - 1; ++i) {
- const Name *name = q->nameAt(i);
- if (const Identifier *id = name->identifier()) {
- const QByteArray spell = QByteArray::fromRawData(id->chars(), id->size());
- if (! (_namespaceNames.contains(spell) || isType(id))) {
- translationUnit()->warning(ast->firstToken(),
- "`%s' is not a namespace or class name",
- spell.constData());
- }
+ if (ast->name && ast->name->name) {
+ if (const Identifier *templId = ast->name->name->identifier()) {
+ const QByteArray id = QByteArray::fromRawData(templId->chars(), templId->size());
+ if (_potentialTypes.contains(id)) {
+ Scope *scope = findScope(_templateDeclarationStack.back());
+ const QList<Symbol *> candidates = _context.lookup(ast->name->name, scope);
+ addTypeUsage(candidates, ast->name);
}
}
}
-
return true;
}
-bool CheckUndefinedSymbols::visit(CastExpressionAST *ast)
+bool CheckUndefinedSymbols::visit(TemplateTypeParameterAST *ast)
{
- if (ast->lparen_token && ast->type_id && ast->rparen_token && ast->expression) {
- if (TypeIdAST *cast_type_id = ast->type_id->asTypeId()) {
- SpecifierListAST *type_specifier = cast_type_id->type_specifier_list;
- if (! cast_type_id->declarator && type_specifier && ! type_specifier->next &&
- type_specifier->value->asNamedTypeSpecifier() && ast->expression &&
- ast->expression->asUnaryExpression()) {
- // this ast node is ambigious, e.g.
- // (a) + b
- // it can be parsed as
- // ((a) + b)
- // or
- // (a) (+b)
- accept(ast->expression);
- return false;
- }
- }
- }
-
+ checkName(ast->name);
return true;
}
-bool CheckUndefinedSymbols::visit(SizeofExpressionAST *ast)
+bool CheckUndefinedSymbols::visit(TemplateDeclarationAST *ast)
{
- if (ast->lparen_token && ast->expression && ast->rparen_token) {
- if (TypeIdAST *type_id = ast->expression->asTypeId()) {
- SpecifierListAST *type_specifier = type_id->type_specifier_list;
- if (! type_id->declarator && type_specifier && ! type_specifier->next &&
- type_specifier->value->asNamedTypeSpecifier()) {
- // this sizeof expression is ambiguos, e.g.
- // sizeof (a)
- // `a' can be a typeid or a nested-expression.
- return false;
- } else if (type_id->declarator
- && type_id->declarator->postfix_declarator_list
- && ! type_id->declarator->postfix_declarator_list->next
- && type_id->declarator->postfix_declarator_list->value->asArrayDeclarator() != 0) {
- // this sizeof expression is ambiguos, e.g.
- // sizeof(a[10])
- // `a' can be a typeid or an expression.
- return false;
- }
- }
- }
-
+ _templateDeclarationStack.append(ast);
return true;
}
-bool CheckUndefinedSymbols::visit(ObjCClassDeclarationAST *ast)
+void CheckUndefinedSymbols::endVisit(TemplateDeclarationAST *)
{
- if (NameAST *nameAST = ast->superclass) {
- bool resolvedSuperClassName = false;
-
- if (const Name *name = nameAST->name) {
- const Identifier *id = name->identifier();
- const QByteArray spell = QByteArray::fromRawData(id->chars(), id->size());
- if (isType(spell))
- resolvedSuperClassName = true;
- }
+ _templateDeclarationStack.takeFirst();
+}
- if (! resolvedSuperClassName) {
- translationUnit()->warning(nameAST->firstToken(),
- "expected class-name after ':' token");
- }
- }
+void CheckUndefinedSymbols::addTypeUsage(ClassOrNamespace *b, NameAST *ast)
+{
+ if (! b)
+ return;
- return true;
+ unsigned startToken = ast->firstToken();
+ if (DestructorNameAST *dtor = ast->asDestructorName())
+ startToken = dtor->identifier_token;
+
+ const Token &tok = tokenAt(startToken);
+ if (tok.generated())
+ return;
+
+ unsigned line, column;
+ getTokenStartPosition(startToken, &line, &column);
+ const unsigned length = tok.length();
+ Use use(line, column, length);
+ _typeUsages.append(use);
+ //qDebug() << "added use" << oo(ast->name) << line << column << length;
}
-bool CheckUndefinedSymbols::visit(ObjCProtocolRefsAST *ast)
+void CheckUndefinedSymbols::addTypeUsage(const QList<Symbol *> &candidates, NameAST *ast)
{
- for (NameListAST *iter = ast->identifier_list; iter; iter = iter->next) {
- if (NameAST *nameAST = iter->value) {
- bool resolvedProtocolName = false;
-
- if (const Name *name = nameAST->name) {
- const Identifier *id = name->identifier();
- const QByteArray spell = QByteArray::fromRawData(id->chars(), id->size());
- if (isProtocol(spell))
- resolvedProtocolName = true;
- }
+ unsigned startToken = ast->firstToken();
+ if (DestructorNameAST *dtor = ast->asDestructorName())
+ startToken = dtor->identifier_token;
- if (!resolvedProtocolName) {
- char after;
+ const Token &tok = tokenAt(startToken);
+ if (tok.generated())
+ return;
- if (iter == ast->identifier_list)
- after = '<';
- else
- after = ',';
+ unsigned line, column;
+ getTokenStartPosition(startToken, &line, &column);
+ const unsigned length = tok.length();
- translationUnit()->warning(nameAST->firstToken(), "expected protocol name after '%c' token", after);
- }
+ foreach (Symbol *c, candidates) {
+ if (c->isUsingDeclaration()) // skip using declarations...
+ continue;
+ else if (c->isUsingNamespaceDirective()) // ... and using namespace directives.
+ continue;
+ else if (c->isTypedef() || c->isNamespace() ||
+ c->isClass() || c->isEnum() ||
+ c->isForwardClassDeclaration() || c->isTypenameArgument()) {
+ Use use(line, column, length);
+ _typeUsages.append(use);
+ //qDebug() << "added use" << oo(ast->name) << line << column << length;
+ break;
}
}
+}
- return false;
+QList<CheckUndefinedSymbols::Use> CheckUndefinedSymbols::typeUsages() const
+{
+ return _typeUsages;
}
-bool CheckUndefinedSymbols::visit(ObjCPropertyDeclarationAST *ast)
+unsigned CheckUndefinedSymbols::startOfTemplateDeclaration(TemplateDeclarationAST *ast) const
{
- for (List<ObjCPropertyDeclaration *> *iter = ast->symbols; iter; iter = iter->next) {
- if (/*Name *getterName = */ iter->value->getterName()) {
- // FIXME: resolve the symbol for the name, and check its signature.
- }
+ if (ast->declaration) {
+ if (TemplateDeclarationAST *templ = ast->declaration->asTemplateDeclaration())
+ return startOfTemplateDeclaration(templ);
- if (/*Name *setterName = */ iter->value->setterName()) {
- // FIXME: resolve the symbol for the name, and check its signature.
- }
+ return ast->declaration->firstToken();
}
- return false;
+ return ast->firstToken();
}
-bool CheckUndefinedSymbols::visit(QtEnumDeclarationAST *ast)
+Scope *CheckUndefinedSymbols::findScope(AST *ast) const
{
- for (NameListAST *iter = ast->enumerator_list; iter; iter = iter->next) {
- if (! iter->value)
- continue;
+ Scope *scope = 0;
- if (SimpleNameAST *enumName = iter->value->asSimpleName()) {
- if (enumName->name) {
- const Identifier *enumId = enumName->name->identifier();
- if (!isType(enumId))// ### we're only checking if the enum name is known as a type name, not as an *enum*.
- translationUnit()->warning(enumName->firstToken(),
- "unknown enum '%s'",
- enumId->chars());
- }
- }
+ if (ast) {
+ unsigned startToken = ast->firstToken();
+ if (TemplateDeclarationAST *templ = ast->asTemplateDeclaration())
+ startToken = startOfTemplateDeclaration(templ);
+
+ const unsigned tokenOffset = tokenAt(startToken).offset;
+ scope = CollectTypes::findScope(tokenOffset, _scopes);
}
- return false;
-}
-bool CheckUndefinedSymbols::visit(QtFlagsDeclarationAST *)
-{
- // ### TODO
- return false;
-}
+ if (! scope)
+ scope = _context.thisDocument()->globalSymbols();
-bool CheckUndefinedSymbols::visit(QtPropertyDeclarationAST *)
-{
- // ### TODO
- return false;
+ return scope;
}
**
**************************************************************************/
-#ifndef CHECKUNDEFINEDSYMBOLS_H
-#define CHECKUNDEFINEDSYMBOLS_H
+#ifndef CPLUSPLUS_CHECKUNDEFINEDSYMBOLS_H
+#define CPLUSPLUS_CHECKUNDEFINEDSYMBOLS_H
#include "CppDocument.h"
-#include "CppBindings.h"
-
+#include "LookupContext.h"
#include <ASTVisitor.h>
#include <QtCore/QSet>
-#include <QtCore/QByteArray>
namespace CPlusPlus {
class CPLUSPLUS_EXPORT CheckUndefinedSymbols: protected ASTVisitor
{
public:
- CheckUndefinedSymbols(Document::Ptr doc);
+ CheckUndefinedSymbols(TranslationUnit *unit, const LookupContext &context);
virtual ~CheckUndefinedSymbols();
- void setGlobalNamespaceBinding(NamespaceBindingPtr globalNamespaceBinding);
+ QList<Document::DiagnosticMessage> operator()(AST *ast);
- void operator()(AST *ast);
+ struct Use { // ### remove me
+ unsigned line;
+ unsigned column;
+ unsigned length;
-protected:
- using ASTVisitor::visit;
+ Use(unsigned line = 0, unsigned column = 0, unsigned length = 0)
+ : line(line), column(column), length(length) {}
+ };
- bool isType(const Identifier *id) const;
- bool isType(const QByteArray &name) const;
+ QList<Use> typeUsages() const;
- void addType(const Name *name);
- void buildTypeMap(Class *klass);
- void buildMemberTypeMap(Symbol *member);
- void buildTypeMap(NamespaceBinding *binding, QSet<NamespaceBinding *> *processed);
- void addProtocol(const Name *name);
- bool isProtocol(const QByteArray &name) const;
+protected:
+ using ASTVisitor::visit;
+ using ASTVisitor::endVisit;
- FunctionDeclaratorAST *currentFunctionDeclarator() const;
- CompoundStatementAST *compoundStatement() const;
- bool qobjectCheck() const;
+ bool warning(unsigned line, unsigned column, const QString &text, unsigned length = 0);
+ bool warning(AST *ast, const QString &text);
- QByteArray templateParameterName(NameAST *ast) const;
- QByteArray templateParameterName(DeclarationAST *ast) const;
+ void checkName(NameAST *ast);
+ void checkNamespace(NameAST *name);
+ void addTypeUsage(ClassOrNamespace *b, NameAST *ast);
+ void addTypeUsage(const QList<Symbol *> &candidates, NameAST *ast);
- virtual bool visit(FunctionDeclaratorAST *ast);
- virtual void endVisit(FunctionDeclaratorAST *ast);
+ virtual bool visit(NamespaceAST *);
+ virtual bool visit(UsingDirectiveAST *);
+ virtual bool visit(SimpleDeclarationAST *);
+ virtual bool visit(NamedTypeSpecifierAST *);
- virtual bool visit(TypeofSpecifierAST *ast);
- virtual bool visit(NamedTypeSpecifierAST *ast);
+ virtual bool visit(SimpleNameAST *ast);
+ virtual bool visit(DestructorNameAST *ast);
+ virtual bool visit(QualifiedNameAST *ast);
+ virtual bool visit(TemplateIdAST *ast);
virtual bool visit(TemplateDeclarationAST *ast);
- virtual void endVisit(TemplateDeclarationAST *);
-
- virtual bool visit(ClassSpecifierAST *ast);
- virtual void endVisit(ClassSpecifierAST *);
-
- virtual bool visit(FunctionDefinitionAST *ast);
- virtual void endVisit(FunctionDefinitionAST *ast);
-
- virtual bool visit(CompoundStatementAST *ast);
- virtual void endVisit(CompoundStatementAST *ast);
-
- virtual bool visit(SimpleDeclarationAST *ast);
- virtual bool visit(BaseSpecifierAST *base);
- virtual bool visit(UsingDirectiveAST *ast);
- virtual bool visit(QualifiedNameAST *ast);
- virtual bool visit(CastExpressionAST *ast);
- virtual bool visit(SizeofExpressionAST *ast);
+ virtual void endVisit(TemplateDeclarationAST *ast);
- virtual bool visit(ObjCClassDeclarationAST *ast);
- virtual bool visit(ObjCProtocolRefsAST *ast);
- virtual bool visit(ObjCPropertyDeclarationAST *ast);
+ virtual bool visit(TypenameTypeParameterAST *ast);
+ virtual bool visit(TemplateTypeParameterAST *ast);
- virtual bool visit(QtEnumDeclarationAST *ast);
- virtual bool visit(QtFlagsDeclarationAST *ast);
- virtual bool visit(QtPropertyDeclarationAST *ast);
+ unsigned startOfTemplateDeclaration(TemplateDeclarationAST *ast) const;
+ Scope *findScope(AST *ast) const;
private:
- Document::Ptr _doc;
- NamespaceBindingPtr _globalNamespaceBinding;
- QList<bool> _qobjectStack;
- QList<FunctionDeclaratorAST *> _functionDeclaratorStack;
+ LookupContext _context;
+ QString _fileName;
+ QList<Document::DiagnosticMessage> _diagnosticMessages;
+ QSet<QByteArray> _potentialTypes;
+ QList<ScopedSymbol *> _scopes;
+ QList<Use> _typeUsages;
QList<TemplateDeclarationAST *> _templateDeclarationStack;
- QList<CompoundStatementAST *> _compoundStatementStack;
- QSet<QByteArray> _types;
- QSet<QByteArray> _protocols;
- QSet<QByteArray> _namespaceNames;
};
} // end of namespace CPlusPlus
-#endif // CHECKUNDEFINEDSYMBOLS_H
+#endif // CPLUSPLUS_CHECKUNDEFINEDSYMBOLS_H
+++ /dev/null
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** Commercial Usage
-**
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
-**
-** GNU Lesser General Public License Usage
-**
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
-**
-**************************************************************************/
-
-#include "CppBindings.h"
-#include "CppDocument.h"
-#include "Overview.h"
-
-#include <CoreTypes.h>
-#include <Symbols.h>
-#include <Literals.h>
-#include <Names.h>
-#include <Scope.h>
-#include <Control.h>
-#include <SymbolVisitor.h>
-
-#include <QtDebug>
-
-using namespace CPlusPlus;
-
-
-////////////////////////////////////////////////////////////////////////////////
-// Location
-////////////////////////////////////////////////////////////////////////////////
-Location::Location()
- : _fileId(0),
- _sourceLocation(0)
-{ }
-
-Location::Location(Symbol *symbol)
- : _fileId(symbol->fileId()),
- _sourceLocation(symbol->sourceLocation())
-{ }
-
-Location::Location(const StringLiteral *fileId, unsigned sourceLocation)
- : _fileId(fileId), _sourceLocation(sourceLocation)
-{ }
-
-////////////////////////////////////////////////////////////////////////////////
-// NamespaceBinding
-////////////////////////////////////////////////////////////////////////////////
-
-NamespaceBinding::NamespaceBinding(NamespaceBinding *parent)
- : parent(parent),
- anonymousNamespaceBinding(0)
-{
- if (parent)
- parent->children.append(this);
-}
-
-NamespaceBinding::~NamespaceBinding()
-{
- qDeleteAll(QList<NamespaceBinding *>(children));
- qDeleteAll(QList<ClassBinding *>(classBindings));
-
- if (parent)
- parent->asNamespaceBinding()->children.removeAll(this);
- parent = 0;
-}
-
-const NameId *NamespaceBinding::name() const
-{
- if (symbols.size()) {
- if (const Name *name = symbols.first()->name()) {
- const NameId *nameId = name->asNameId();
- Q_ASSERT(nameId != 0);
-
- return nameId;
- }
- }
-
- return 0;
-}
-
-const Identifier *NamespaceBinding::identifier() const
-{
- if (const NameId *nameId = name())
- return nameId->identifier();
-
- return 0;
-}
-
-NamespaceBinding *NamespaceBinding::globalNamespaceBinding()
-{
- NamespaceBinding *it = this;
-
- for (; it; it = it->parent) {
- if (! it->parent)
- break;
- }
-
- return it;
-}
-
-Binding *NamespaceBinding::findClassOrNamespaceBinding(const Identifier *id, QSet<Binding *> *processed)
-{
- if (processed->contains(this))
- return 0;
-
- processed->insert(this);
-
- if (id->isEqualTo(identifier()))
- return const_cast<NamespaceBinding *>(this);
-
- foreach (NamespaceBinding *nestedNamespaceBinding, children) {
- if (id->isEqualTo(nestedNamespaceBinding->identifier()))
- return nestedNamespaceBinding;
- }
-
- foreach (ClassBinding *classBinding, classBindings) {
- if (id->isEqualTo(classBinding->identifier()))
- return classBinding;
- }
-
- foreach (NamespaceBinding *u, usings) {
- if (Binding *b = u->findClassOrNamespaceBinding(id, processed))
- return b;
- }
-
- if (parent)
- return parent->findClassOrNamespaceBinding(id, processed);
-
- return 0;
-}
-
-ClassBinding *NamespaceBinding::findClassBinding(const Name *name, QSet<Binding *> *processed)
-{
- if (! name)
- return 0;
-
- if (processed->contains(this))
- return 0;
-
- if (const QualifiedNameId *q = name->asQualifiedNameId()) {
- Binding *current = this;
-
- for (unsigned i = 0; i < q->nameCount(); ++i) {
- const Identifier *nameId = q->nameAt(i)->identifier();
- if (! nameId)
- return 0;
-
- QSet<Binding *> visited;
- Binding *binding = current->findClassOrNamespaceBinding(nameId, &visited); // ### TODO: check recursion.
- if (! binding)
- return 0;
-
- current = binding;
- }
-
- return current->asClassBinding();
- }
-
- processed->insert(this);
-
- const Identifier *id = name->identifier();
-
- foreach (ClassBinding *classBinding, classBindings) {
- if (id->isEqualTo(classBinding->identifier()))
- return classBinding;
- }
-
- if (parent)
- return parent->findClassBinding(name, processed);
-
- foreach (NamespaceBinding *u, usings) {
- if (ClassBinding *classBinding = u->findClassBinding(name, processed))
- return classBinding;
- }
-
- return 0;
-}
-
-NamespaceBinding *NamespaceBinding::findNamespaceBinding(const Name *name)
-{
- if (! name)
- return anonymousNamespaceBinding;
-
- else if (const NameId *nameId = name->asNameId())
- return findNamespaceBindingForNameId(nameId, /*lookAtParent = */ true);
-
- else if (const QualifiedNameId *q = name->asQualifiedNameId()) {
- NamespaceBinding *current = this;
-
- for (unsigned i = 0; i < q->nameCount(); ++i) {
- const NameId *namespaceName = q->nameAt(i)->asNameId();
- if (! namespaceName)
- return 0;
-
- bool lookAtParent = false;
- if (i == 0)
- lookAtParent = true;
-
- NamespaceBinding *binding = current->findNamespaceBindingForNameId(namespaceName, lookAtParent);
- if (! binding)
- return 0;
-
- current = binding;
- }
-
- return current;
- }
-
- // invalid binding
- return 0;
-}
-
-NamespaceBinding *NamespaceBinding::findNamespaceBindingForNameId(const NameId *name,
- bool lookAtParentNamespace)
-{
- QSet<NamespaceBinding *> processed;
- return findNamespaceBindingForNameId_helper(name, lookAtParentNamespace, &processed);
-}
-
-NamespaceBinding *NamespaceBinding::findNamespaceBindingForNameId_helper(const NameId *name,
- bool lookAtParentNamespace,
- QSet<NamespaceBinding *> *processed)
-{
- if (processed->contains(this))
- return 0;
-
- processed->insert(this);
-
- foreach (NamespaceBinding *binding, children) {
- const Name *bindingName = binding->name();
-
- if (! bindingName)
- continue;
-
- if (const NameId *bindingNameId = bindingName->asNameId()) {
- if (name->isEqualTo(bindingNameId))
- return binding;
- }
- }
-
- foreach (NamespaceBinding *u, usings) {
- if (NamespaceBinding *b = u->findNamespaceBindingForNameId_helper(name, lookAtParentNamespace, processed)) {
- return b;
- }
- }
-
- if (lookAtParentNamespace && parent)
- return parent->findNamespaceBindingForNameId_helper(name, lookAtParentNamespace, processed);
-
- return 0;
-}
-
-NamespaceBinding *NamespaceBinding::findOrCreateNamespaceBinding(Namespace *symbol)
-{
- if (NamespaceBinding *binding = findNamespaceBinding(symbol->name())) {
- int index = 0;
-
- for (; index < binding->symbols.size(); ++index) {
- Namespace *ns = binding->symbols.at(index);
-
- if (ns == symbol)
- break;
- }
-
- if (index == binding->symbols.size())
- binding->symbols.append(symbol);
-
- return binding;
- }
-
- NamespaceBinding *binding = new NamespaceBinding(this);
- binding->symbols.append(symbol);
-
- if (! symbol->name()) {
- Q_ASSERT(! anonymousNamespaceBinding);
-
- anonymousNamespaceBinding = binding;
- }
-
- return binding;
-}
-
-static void closure(const Location &loc,
- NamespaceBinding *binding, const Name *name,
- QList<NamespaceBinding *> *bindings)
-{
- if (bindings->contains(binding))
- return;
-
- bindings->append(binding);
-
- Q_ASSERT(name->isNameId());
-
- const Identifier *id = name->asNameId()->identifier();
- bool ignoreUsingDirectives = false;
-
- foreach (Namespace *symbol, binding->symbols) {
- Scope *scope = symbol->members();
-
- for (Symbol *symbol = scope->lookat(id); symbol; symbol = symbol->next()) {
- if (symbol->name() != name || ! symbol->isNamespace())
- continue;
-
- const Location l(symbol);
-
- if (l.fileId() == loc.fileId() && l.sourceLocation() < loc.sourceLocation()) {
- ignoreUsingDirectives = true;
- break;
- }
- }
- }
-
- if (ignoreUsingDirectives)
- return;
-
- foreach (NamespaceBinding *u, binding->usings)
- closure(loc, u, name, bindings);
-}
-
-
-NamespaceBinding *NamespaceBinding::resolveNamespace(const Location &loc,
- const Name *name,
- bool lookAtParent)
-{
- if (! name)
- return 0;
-
- else if (const NameId *nameId = name->asNameId()) {
- QList<NamespaceBinding *> bindings;
- closure(loc, this, nameId, &bindings);
-
- QList<NamespaceBinding *> results;
-
- foreach (NamespaceBinding *binding, bindings) {
- if (NamespaceBinding *b = binding->findNamespaceBinding(nameId))
- results.append(b);
- }
-
- if (results.size() == 1)
- return results.at(0);
-
- else if (results.size() > 1) {
- // ### FIXME: return 0;
- return results.at(0);
- }
-
- else if (parent && lookAtParent)
- return parent->resolveNamespace(loc, name);
-
- } else if (const QualifiedNameId *q = name->asQualifiedNameId()) {
- if (q->nameCount() == 1) {
- Q_ASSERT(q->isGlobal());
-
- return globalNamespaceBinding()->resolveNamespace(loc, q->nameAt(0));
- }
-
- NamespaceBinding *current = this;
- if (q->isGlobal())
- current = globalNamespaceBinding();
-
- current = current->resolveNamespace(loc, q->nameAt(0));
- for (unsigned i = 1; current && i < q->nameCount(); ++i)
- current = current->resolveNamespace(loc, q->nameAt(i), false);
-
- return current;
- }
-
- return 0;
-}
-
-// ### rewrite me
-QByteArray NamespaceBinding::qualifiedId() const
-{
- if (! parent)
- return "<root>";
-
- QByteArray s;
-
- s.append(parent->qualifiedId());
- s.append("::");
-
- if (const Identifier *id = identifier())
- s.append(id->chars(), id->size());
-
- else
- s.append("<anonymous>");
-
- return s;
-}
-
-// ### rewrite me
-QByteArray ClassBinding::qualifiedId() const
-{
- QByteArray s = parent->qualifiedId();
- s += "::";
-
- if (const Identifier *id = identifier())
- s.append(id->chars(), id->size());
-
- else
- s.append("<anonymous>");
-
- return s;
-}
-
-Binding *ClassBinding::findClassOrNamespaceBinding(const Identifier *id, QSet<Binding *> *processed)
-{
- if (id->isEqualTo(identifier()))
- return this;
-
- if (processed->contains(this))
- return 0;
-
- processed->insert(this);
-
- foreach (ClassBinding *nestedClassBinding, children) {
- if (id->isEqualTo(nestedClassBinding->identifier()))
- return nestedClassBinding;
- }
-
- foreach (ClassBinding *baseClassBinding, baseClassBindings) {
- if (! baseClassBinding)
- continue;
-
- else if (Binding *b = baseClassBinding->findClassOrNamespaceBinding(id, processed))
- return b;
- }
-
- if (parent)
- return parent->findClassOrNamespaceBinding(id, processed);
-
- return 0;
-}
-
-ClassBinding *ClassBinding::findClassBinding(const Name *name, QSet<Binding *> *processed)
-{
- if (! name)
- return 0;
-
- if (processed->contains(this))
- return 0;
-
- processed->insert(this);
-
- if (const QualifiedNameId *q = name->asQualifiedNameId()) {
- Binding *currentBinding = this;
-
- for (unsigned i = 0; i < q->nameCount() - 1; ++i) {
- const Identifier *id = q->nameAt(i)->identifier();
- if (! id)
- return 0;
-
- Binding *classOrNamespaceBinding = currentBinding->findClassOrNamespaceBinding(id, processed);
-
- if (! classOrNamespaceBinding)
- return 0;
-
- currentBinding = classOrNamespaceBinding;
- }
-
- if (currentBinding)
- return currentBinding->findClassBinding(q->unqualifiedNameId(), processed);
-
- return 0;
- }
-
- if (const Identifier *id = name->identifier()) {
- if (id->isEqualTo(identifier()))
- return this;
-
- foreach (ClassBinding *nestedClassBinding, children) {
- if (const Identifier *nestedClassId = nestedClassBinding->identifier()) {
- if (nestedClassId->isEqualTo(id))
- return nestedClassBinding;
- }
- }
-
- if (parent)
- return parent->findClassBinding(name, processed);
- }
-
- return 0;
-}
-
-static int depth;
-
-void NamespaceBinding::dump()
-{
- qDebug() << QByteArray(depth, ' ').constData() << "namespace" << qualifiedId().constData()
- << " # " << symbols.size();
-
- ++depth;
-
- foreach (ClassBinding *classBinding, classBindings) {
- classBinding->dump();
- }
-
- foreach (NamespaceBinding *child, children) {
- child->dump();
- }
-
- --depth;
-}
-
-void ClassBinding::dump()
-{
- qDebug() << QByteArray(depth, ' ').constData() << "class" << qualifiedId().constData()
- << " # " << symbols.size();
-
- ++depth;
-
- foreach (ClassBinding *classBinding, children) {
- classBinding->dump();
- }
-
- --depth;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ClassBinding
-////////////////////////////////////////////////////////////////////////////////
-ClassBinding::ClassBinding(NamespaceBinding *parent)
- : parent(parent)
-{
- parent->classBindings.append(this);
-}
-
-ClassBinding::ClassBinding(ClassBinding *parentClass)
- : parent(parentClass)
-{
- parentClass->children.append(this);
-}
-
-ClassBinding::~ClassBinding()
-{
- qDeleteAll(QList<ClassBinding *>(children));
- if (NamespaceBinding *nsBinding = parent->asNamespaceBinding())
- nsBinding->classBindings.removeAll(this);
- if (ClassBinding *classBinding = parent->asClassBinding())
- classBinding->children.removeAll(this);
- parent = 0;
-}
-
-const Name *ClassBinding::name() const
-{
- if (symbols.isEmpty())
- return 0;
-
- return symbols.first()->name();
-}
-
-const Identifier *ClassBinding::identifier() const
-{
- if (const Name *n = name())
- return n->identifier();
-
- return 0;
-}
-
-namespace {
-
-////////////////////////////////////////////////////////////////////////////////
-// Binder
-////////////////////////////////////////////////////////////////////////////////
-
-class Binder: protected SymbolVisitor
-{
-public:
- Binder(NamespaceBinding *globals);
- virtual ~Binder();
-
- NamespaceBinding *operator()(Document::Ptr doc, const Snapshot &snapshot)
- {
- namespaceBinding = _globals;
- const Snapshot previousSnapshot = _snapshot;
-
- _snapshot = snapshot;
- (void) bind(doc);
- _snapshot = previousSnapshot;
-
- return _globals;
- }
-
- Snapshot _snapshot;
-
-protected:
- NamespaceBinding *bind(Document::Ptr doc)
- {
- QSet<QString> processed;
- return bind(doc, &processed);
- }
-
- NamespaceBinding *bind(Document::Ptr doc, QSet<QString> *processed)
- {
- if (processed->contains(doc->fileName()))
- return 0;
-
- processed->insert(doc->fileName());
-
- foreach (const Document::Include &i, doc->includes()) {
- if (Document::Ptr includedDoc = _snapshot.document(i.fileName())) {
- /*NamepaceBinding *binding = */ bind(includedDoc, processed);
- }
- }
-
- Namespace *ns = doc->globalNamespace();
- _globals->symbols.append(ns);
-
- for (unsigned i = 0; i < ns->memberCount(); ++i) {
- (void) bind(ns->memberAt(i), _globals);
- }
-
- return _globals;
- }
-
- NamespaceBinding *bind(Symbol *symbol, NamespaceBinding *binding);
- NamespaceBinding *findOrCreateNamespaceBinding(Namespace *symbol);
- NamespaceBinding *resolveNamespace(const Location &loc, const Name *name);
-
- NamespaceBinding *switchNamespaceBinding(NamespaceBinding *binding);
-
- ClassBinding *findOrCreateClassBinding(Class *classSymbol);
- ClassBinding *findClassBinding(const Name *name);
-
- ClassBinding *switchClassBinding(ClassBinding *binding);
-
- using SymbolVisitor::visit;
-
- virtual bool visit(Namespace *);
- virtual bool visit(UsingNamespaceDirective *);
- virtual bool visit(Class *);
- virtual bool visit(Function *);
- virtual bool visit(Block *);
-
-private:
- NamespaceBinding *_globals;
- NamespaceBinding *namespaceBinding;
- ClassBinding *classBinding;
-};
-
-Binder::Binder(NamespaceBinding *globals)
- : _globals(globals),
- namespaceBinding(0),
- classBinding(0)
-{ }
-
-Binder::~Binder()
-{ }
-
-NamespaceBinding *Binder::bind(Symbol *symbol, NamespaceBinding *binding)
-{
- NamespaceBinding *previousBinding = switchNamespaceBinding(binding);
- accept(symbol);
- return switchNamespaceBinding(previousBinding);
-}
-
-NamespaceBinding *Binder::findOrCreateNamespaceBinding(Namespace *symbol)
-{ return namespaceBinding->findOrCreateNamespaceBinding(symbol); }
-
-NamespaceBinding *Binder::resolveNamespace(const Location &loc, const Name *name)
-{
- if (! namespaceBinding)
- return 0;
-
- return namespaceBinding->resolveNamespace(loc, name);
-}
-
-NamespaceBinding *Binder::switchNamespaceBinding(NamespaceBinding *binding)
-{
- NamespaceBinding *previousBinding = namespaceBinding;
- namespaceBinding = binding;
- return previousBinding;
-}
-
-ClassBinding *Binder::findOrCreateClassBinding(Class *classSymbol)
-{
- // ### FINISH ME
- ClassBinding *binding = 0;
-
- if (classBinding)
- binding = new ClassBinding(classBinding);
- else
- binding = new ClassBinding(namespaceBinding);
-
- binding->symbols.append(classSymbol);
- return binding;
-}
-
-ClassBinding *Binder::findClassBinding(const Name *name)
-{
- QSet<Binding *> processed;
-
- if (classBinding) {
- if (ClassBinding *k = classBinding->findClassBinding(name, &processed))
- return k;
-
- processed.clear();
- }
-
- if (namespaceBinding)
- return namespaceBinding->findClassBinding(name, &processed);
-
- return 0;
-}
-
-ClassBinding *Binder::switchClassBinding(ClassBinding *binding)
-{
- ClassBinding *previousClassBinding = classBinding;
- classBinding = binding;
- return previousClassBinding;
-}
-
-bool Binder::visit(Namespace *symbol)
-{
- NamespaceBinding *binding = findOrCreateNamespaceBinding(symbol);
-
- for (unsigned i = 0; i < symbol->memberCount(); ++i) {
- Symbol *member = symbol->memberAt(i);
-
- bind(member, binding);
- }
-
- return false;
-}
-
-bool Binder::visit(UsingNamespaceDirective *u)
-{
- NamespaceBinding *resolved = resolveNamespace(Location(u), u->name());
-
- if (! resolved)
- return false;
-
- namespaceBinding->usings.append(resolved);
-
- return false;
-}
-
-bool Binder::visit(Class *classSymbol)
-{
- ClassBinding *binding = findOrCreateClassBinding(classSymbol);
- ClassBinding *previousClassBinding = switchClassBinding(binding);
-
- for (unsigned i = 0; i < classSymbol->baseClassCount(); ++i) {
- BaseClass *baseClass = classSymbol->baseClassAt(i);
- ClassBinding *baseClassBinding = findClassBinding(baseClass->name());
- binding->baseClassBindings.append(baseClassBinding);
- }
-
- for (unsigned i = 0; i < classSymbol->memberCount(); ++i)
- accept(classSymbol->memberAt(i));
-
- (void) switchClassBinding(previousClassBinding);
-
- return false;
-}
-
-bool Binder::visit(Function *)
-{ return false; }
-
-bool Binder::visit(Block *)
-{ return false; }
-
-} // end of anonymous namespace
-
-static NamespaceBinding *find_helper(Namespace *symbol, NamespaceBinding *binding,
- QSet<NamespaceBinding *> *processed)
-{
- if (binding && ! processed->contains(binding)) {
- processed->insert(binding);
-
- if (binding->symbols.contains(symbol))
- return binding;
-
- foreach (NamespaceBinding *nestedBinding, binding->children) {
- if (NamespaceBinding *ns = find_helper(symbol, nestedBinding, processed))
- return ns;
- }
-
- if (NamespaceBinding *a = find_helper(symbol, binding->anonymousNamespaceBinding, processed))
- return a;
- }
-
- return 0;
-}
-
-static ClassBinding *find_helper(Class *symbol, Binding *binding,
- QSet<Binding *> *processed)
-{
- if (binding && ! processed->contains(binding)) {
- processed->insert(binding);
-
- if (NamespaceBinding *namespaceBinding = binding->asNamespaceBinding()) {
- foreach (ClassBinding *classBinding, namespaceBinding->classBindings) {
- if (ClassBinding *c = find_helper(symbol, classBinding, processed))
- return c;
- }
-
- foreach (NamespaceBinding *nestedBinding, namespaceBinding->children) {
- if (ClassBinding *c = find_helper(symbol, nestedBinding, processed))
- return c;
- }
-
- if (ClassBinding *a = find_helper(symbol, namespaceBinding->anonymousNamespaceBinding, processed))
- return a;
-
- } else if (ClassBinding *classBinding = binding->asClassBinding()) {
- foreach (Class *klass, classBinding->symbols) {
- if (klass == symbol)
- return classBinding;
- }
-
- foreach (ClassBinding *nestedClassBinding, classBinding->children) {
- if (ClassBinding *c = find_helper(symbol, nestedClassBinding, processed))
- return c;
- }
-
-#if 0 // ### FIXME
- if (ClassBinding *a = find_helper(symbol, classBinding->anonymousClassBinding, processed))
- return a;
-#endif
- }
- }
-
- return 0;
-}
-
-NamespaceBinding *NamespaceBinding::find(Namespace *symbol, NamespaceBinding *binding)
-{
- QSet<NamespaceBinding *> processed;
- return find_helper(symbol, binding, &processed);
-}
-
-ClassBinding *NamespaceBinding::find(Class *symbol, NamespaceBinding *binding)
-{
- QSet<Binding *> processed;
- return find_helper(symbol, binding, &processed);
-}
-
-NamespaceBindingPtr CPlusPlus::bind(Document::Ptr doc, Snapshot snapshot)
-{
- NamespaceBindingPtr global(new NamespaceBinding());
-
- Binder bind(global.data());
- bind(doc, snapshot);
- return global;
-}
-
+++ /dev/null
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** Commercial Usage
-**
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
-**
-** GNU Lesser General Public License Usage
-**
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
-**
-**************************************************************************/
-
-#ifndef CPPBINDINGS_H
-#define CPPBINDINGS_H
-
-#include "CppDocument.h"
-
-#include <QtCore/QList>
-#include <QtCore/QSharedPointer>
-#include <QtCore/QString>
-#include <QtCore/QByteArray>
-
-namespace CPlusPlus {
-
-class Location;
-class Binding;
-class NamespaceBinding;
-class ClassBinding;
-
-typedef QSharedPointer<Binding> BindingPtr;
-typedef QSharedPointer<ClassBinding> ClassBindingPtr;
-typedef QSharedPointer<NamespaceBinding> NamespaceBindingPtr;
-
-class CPLUSPLUS_EXPORT Location
-{
-public:
- Location();
- Location(Symbol *symbol);
- Location(const StringLiteral *fileId, unsigned sourceLocation);
-
- inline bool isValid() const
- { return _fileId != 0; }
-
- inline operator bool() const
- { return _fileId != 0; }
-
- inline const StringLiteral *fileId() const
- { return _fileId; }
-
- inline unsigned sourceLocation() const
- { return _sourceLocation; }
-
-private:
- const StringLiteral *_fileId;
- unsigned _sourceLocation;
-};
-
-class CPLUSPLUS_EXPORT Binding
-{
- Q_DISABLE_COPY(Binding)
-
-public:
- Binding() {}
- virtual ~Binding() {}
-
- virtual QByteArray qualifiedId() const = 0;
- virtual NamespaceBinding *asNamespaceBinding() { return 0; }
- virtual ClassBinding *asClassBinding() { return 0; }
-
- virtual ClassBinding *findClassBinding(const Name *name, QSet<Binding *> *processed) = 0;
- virtual Binding *findClassOrNamespaceBinding(const Identifier *id, QSet<Binding *> *processed) = 0;
-};
-
-class CPLUSPLUS_EXPORT NamespaceBinding: public Binding
-{
-public:
- /// Constructs a binding with the given parent.
- NamespaceBinding(NamespaceBinding *parent = 0);
-
- /// Destroys the binding.
- virtual ~NamespaceBinding();
-
- /// Returns this binding's name.
- const NameId *name() const;
-
- /// Returns this binding's identifier.
- const Identifier *identifier() const;
-
- /// Returns the binding for the global namespace (aka ::).
- NamespaceBinding *globalNamespaceBinding();
-
- /// Returns the binding for the given namespace symbol.
- NamespaceBinding *findNamespaceBinding(const Name *name);
-
- /// Returns the binding associated with the given symbol.
- NamespaceBinding *findOrCreateNamespaceBinding(Namespace *symbol);
-
- NamespaceBinding *resolveNamespace(const Location &loc,
- const Name *name,
- bool lookAtParent = true);
-
- virtual ClassBinding *findClassBinding(const Name *name, QSet<Binding *> *processed);
- virtual Binding *findClassOrNamespaceBinding(const Identifier *id, QSet<Binding *> *processed);
-
- /// Helpers.
- virtual QByteArray qualifiedId() const;
- void dump();
-
- virtual NamespaceBinding *asNamespaceBinding() { return this; }
-
- static NamespaceBinding *find(Namespace *symbol, NamespaceBinding *binding);
- static ClassBinding *find(Class *symbol, NamespaceBinding *binding);
-
-private:
- NamespaceBinding *findNamespaceBindingForNameId(const NameId *name,
- bool lookAtParentNamespace);
-
- NamespaceBinding *findNamespaceBindingForNameId_helper(const NameId *name,
- bool lookAtParentNamespace,
- QSet<NamespaceBinding *> *processed);
-
-public: // attributes
- /// This binding's parent.
- NamespaceBinding *parent;
-
- /// Binding for anonymous namespace symbols.
- NamespaceBinding *anonymousNamespaceBinding;
-
- /// This binding's connections.
- QList<NamespaceBinding *> children;
-
- /// This binding's list of using namespaces.
- QList<NamespaceBinding *> usings;
-
- /// This binding's namespace symbols.
- QList<Namespace *> symbols;
-
- QList<ClassBinding *> classBindings;
-};
-
-class CPLUSPLUS_EXPORT ClassBinding: public Binding
-{
-public:
- ClassBinding(NamespaceBinding *parent);
- ClassBinding(ClassBinding *parentClass);
- virtual ~ClassBinding();
-
- virtual ClassBinding *asClassBinding() { return this; }
-
- /// Returns this binding's name.
- const Name *name() const;
-
- /// Returns this binding's identifier.
- const Identifier *identifier() const;
- virtual QByteArray qualifiedId() const;
-
- virtual ClassBinding *findClassBinding(const Name *name, QSet<Binding *> *processed);
- virtual Binding *findClassOrNamespaceBinding(const Identifier *id, QSet<Binding *> *processed);
-
- void dump();
-
-public: // attributes
- Binding *parent;
-
- QList<ClassBinding *> children;
-
- /// This binding's class symbols.
- QList<Class *> symbols;
-
- /// Bindings for the base classes.
- QList<ClassBinding *> baseClassBindings;
-};
-
-CPLUSPLUS_EXPORT NamespaceBindingPtr bind(Document::Ptr doc, Snapshot snapshot);
-
-} // end of namespace CPlusPlus
-
-#endif // CPPBINDINGS_H
**************************************************************************/
#include "CppDocument.h"
-#include "CppBindings.h"
#include "FastPreprocessor.h"
+#include "LookupContext.h"
+#include "Overview.h"
#include <Control.h>
#include <TranslationUnit.h>
#include <Semantic.h>
#include <Literals.h>
#include <Symbols.h>
+#include <Names.h>
#include <AST.h>
#include <Scope.h>
+#include <SymbolVisitor.h>
#include <QtCore/QByteArray>
#include <QtCore/QBitArray>
namespace {
+class FindScopeAt: protected SymbolVisitor
+{
+ TranslationUnit *_unit;
+ unsigned _line;
+ unsigned _column;
+ Scope *_scope;
+
+public:
+ FindScopeAt(TranslationUnit *unit, unsigned line, unsigned column)
+ : _unit(unit), _line(line), _column(column), _scope(0) {}
+
+ Scope *operator()(Symbol *symbol)
+ {
+ accept(symbol);
+ return _scope;
+ }
+
+protected:
+ bool process(ScopedSymbol *symbol)
+ {
+ if (! _scope) {
+ Scope *scope = symbol->members();
+
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ accept(scope->symbolAt(i));
+
+ if (_scope)
+ return false;
+ }
+
+ unsigned startLine, startColumn;
+ _unit->getPosition(symbol->startOffset(), &startLine, &startColumn);
+
+ if (_line > startLine || (_line == startLine && _column >= startColumn)) {
+ unsigned endLine, endColumn;
+ _unit->getPosition(symbol->endOffset(), &endLine, &endColumn);
+
+ if (_line < endLine || (_line == endLine && _column < endColumn))
+ _scope = scope;
+ }
+ }
+
+ return false;
+ }
+
+ using SymbolVisitor::visit;
+
+ virtual bool preVisit(Symbol *)
+ { return ! _scope; }
+
+ virtual bool visit(UsingNamespaceDirective *) { return false; }
+ virtual bool visit(UsingDeclaration *) { return false; }
+ virtual bool visit(NamespaceAlias *) { return false; }
+ virtual bool visit(Declaration *) { return false; }
+ virtual bool visit(Argument *) { return false; }
+ virtual bool visit(TypenameArgument *) { return false; }
+ virtual bool visit(BaseClass *) { return false; }
+ virtual bool visit(ForwardClassDeclaration *) { return false; }
+
+ virtual bool visit(Enum *symbol)
+ { return process(symbol); }
+
+ virtual bool visit(Function *symbol)
+ { return process(symbol); }
+
+ virtual bool visit(Namespace *symbol)
+ { return process(symbol); }
+
+ virtual bool visit(Class *symbol)
+ { return process(symbol); }
+
+ virtual bool visit(Block *symbol)
+ { return process(symbol); }
+
+ // Objective-C
+ virtual bool visit(ObjCBaseClass *) { return false; }
+ virtual bool visit(ObjCBaseProtocol *) { return false; }
+ virtual bool visit(ObjCForwardClassDeclaration *) { return false; }
+ virtual bool visit(ObjCForwardProtocolDeclaration *) { return false; }
+ virtual bool visit(ObjCPropertyDeclaration *) { return false; }
+
+ virtual bool visit(ObjCClass *symbol)
+ { return process(symbol); }
+
+ virtual bool visit(ObjCProtocol *symbol)
+ { return process(symbol); }
+
+ virtual bool visit(ObjCMethod *symbol)
+ { return process(symbol); }
+};
+
class DocumentDiagnosticClient : public DiagnosticClient
{
enum { MAX_MESSAGE_COUNT = 10 };
localFileName.size());
_translationUnit = new TranslationUnit(_control, fileId);
_translationUnit->setQtMocRunEnabled(true);
- _translationUnit->setCxxOxEnabled(false);
+ _translationUnit->setCxxOxEnabled(true);
_translationUnit->setObjCEnabled(true);
(void) _control->switchTranslationUnit(_translationUnit);
}
_globalNamespace = globalNamespace;
}
-Symbol *Document::findSymbolAt(unsigned line, unsigned column) const
+Scope *Document::scopeAt(unsigned line, unsigned column)
{
- return findSymbolAt(line, column, globalSymbols());
+ FindScopeAt findScopeAt(_translationUnit, line, column);
+ if (Scope *scope = findScopeAt(_globalNamespace))
+ return scope;
+ return globalSymbols();
}
-Symbol *Document::findSymbolAt(unsigned line, unsigned column, Scope *scope) const
+Symbol *Document::lastVisibleSymbolAt(unsigned line, unsigned column) const
+{
+ return lastVisibleSymbolAt(line, column, globalSymbols());
+}
+
+Symbol *Document::lastVisibleSymbolAt(unsigned line, unsigned column, Scope *scope) const
{
Symbol *previousSymbol = 0;
if (previousSymbol) {
if (ScopedSymbol *scoped = previousSymbol->asScopedSymbol()) {
- if (Symbol *member = findSymbolAt(line, column, scoped->members()))
+ if (Symbol *member = lastVisibleSymbolAt(line, column, scoped->members()))
return member;
}
}
return newDoc;
}
-QSharedPointer<NamespaceBinding> Snapshot::globalNamespaceBinding(Document::Ptr doc) const
-{
- return CPlusPlus::bind(doc, *this);
-}
-
Document::Ptr Snapshot::document(const QString &fileName) const
{
return _documents.value(fileName);
}
}
}
+
+namespace {
+class FindMatchingDefinition: public SymbolVisitor
+{
+ Symbol *_declaration;
+ QList<Function *> _result;
+
+public:
+ FindMatchingDefinition(Symbol *declaration)
+ : _declaration(declaration) {}
+
+ QList<Function *> result() const { return _result; }
+
+ using SymbolVisitor::visit;
+
+ virtual bool visit(Function *fun)
+ {
+ if (_declaration->identifier()->isEqualTo(fun->identifier()))
+ _result.append(fun);
+
+ return false;
+ }
+
+ virtual bool visit(Block *)
+ {
+ return false;
+ }
+};
+} // end of anonymous namespace
+
+Symbol *Snapshot::findMatchingDefinition(Symbol *symbol) const
+{
+ if (! symbol->identifier())
+ return 0;
+
+ Document::Ptr thisDocument = document(QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()));
+ if (! thisDocument) {
+ qWarning() << "undefined document:" << symbol->fileName();
+ return 0;
+ }
+
+ LookupContext thisContext(thisDocument, *this);
+ const QList<Symbol *> declarationCandidates = thisContext.lookup(symbol->name(), symbol->scope());
+ if (declarationCandidates.isEmpty()) {
+ qWarning() << "unresolved declaration:" << symbol->fileName() << symbol->line() << symbol->column();
+ return 0;
+ }
+
+ Symbol *declaration = declarationCandidates.first();
+ Function *declarationTy = declaration->type()->asFunctionType();
+ if (! declarationTy) {
+ qWarning() << "not a function:" << declaration->fileName() << declaration->line() << declaration->column();
+ return 0;
+ }
+
+ foreach (Document::Ptr doc, *this) {
+ if (! doc->control()->findIdentifier(declaration->identifier()->chars(),
+ declaration->identifier()->size()))
+ continue;
+
+ FindMatchingDefinition candidates(declaration);
+ candidates.accept(doc->globalNamespace());
+
+ const QList<Function *> result = candidates.result();
+ if (! result.isEmpty()) {
+ LookupContext context(doc, *this);
+
+ QList<Function *> viableFunctions;
+
+ ClassOrNamespace *enclosingType = context.lookupType(declaration);
+ if (! enclosingType)
+ continue; // nothing to do
+
+ foreach (Function *fun, result) {
+ const QList<Symbol *> declarations = context.lookup(fun->name(), fun->scope());
+ if (declarations.isEmpty())
+ continue;
+
+ else if (enclosingType == context.lookupType(declarations.first()))
+ viableFunctions.append(fun);
+ }
+
+ if (viableFunctions.isEmpty())
+ continue;
+
+ else if (viableFunctions.length() == 1)
+ return viableFunctions.first();
+
+ Function *best = 0;
+
+ foreach (Function *fun, viableFunctions) {
+ if (fun->identity()->isEqualTo(declaration->identity()))
+ continue;
+
+ else if (fun->argumentCount() == declarationTy->argumentCount()) {
+ if (! best)
+ best = fun;
+
+ unsigned argc = 0;
+ for (; argc < declarationTy->argumentCount(); ++argc) {
+ Symbol *arg = fun->argumentAt(argc);
+ Symbol *otherArg = declarationTy->argumentAt(argc);
+ if (! arg->type().isEqualTo(otherArg->type()))
+ break;
+ }
+
+ if (argc == declarationTy->argumentCount())
+ best = fun;
+ }
+ }
+
+ if (! best)
+ best = viableFunctions.first();
+
+ return best;
+ }
+ }
+
+ return 0;
+}
**
**************************************************************************/
-#ifndef CPPDOCUMENT_H
-#define CPPDOCUMENT_H
+#ifndef CPLUSPLUS_CPPDOCUMENT_H
+#define CPLUSPLUS_CPPDOCUMENT_H
#include <CPlusPlusForwardDeclarations.h>
#include "Macro.h"
class Macro;
class MacroArgumentReference;
-class NamespaceBinding;
class CPLUSPLUS_EXPORT Document
{
QList<Macro> definedMacros() const
{ return _definedMacros; }
- Symbol *findSymbolAt(unsigned line, unsigned column) const;
+ Symbol *lastVisibleSymbolAt(unsigned line, unsigned column) const;
+ Scope *scopeAt(unsigned line, unsigned column);
QByteArray source() const;
void setSource(const QByteArray &source);
public:
DiagnosticMessage(int level, const QString &fileName,
- int line, int column,
- const QString &text)
+ unsigned line, unsigned column,
+ const QString &text,
+ unsigned length = 0)
: _level(level),
_fileName(fileName),
_line(line),
_column(column),
+ _length(length),
_text(text)
{ }
unsigned column() const
{ return _column; }
+ unsigned length() const
+ { return _length; }
+
QString text() const
{ return _text; }
QString _fileName;
unsigned _line;
unsigned _column;
+ unsigned _length;
QString _text;
};
const UndefinedMacroUse *findUndefinedMacroUseAt(unsigned offset) const;
private:
- Symbol *findSymbolAt(unsigned line, unsigned column, Scope *scope) const;
+ Symbol *lastVisibleSymbolAt(unsigned line, unsigned column, Scope *scope) const;
private:
QString _fileName;
Document::Ptr documentFromSource(const QByteArray &preprocessedCode,
const QString &fileName) const;
- QSharedPointer<NamespaceBinding> globalNamespaceBinding(Document::Ptr doc) const;
+ Symbol *findMatchingDefinition(Symbol *symbol) const;
private:
void simplified_helper(Document::Ptr doc, Snapshot *snapshot) const;
} // end of namespace CPlusPlus
-#endif // CPPDOCUMENT_H
+#endif // CPLUSPLUS_CPPDOCUMENT_H
**
**************************************************************************/
-#ifndef DEPENDENCYTABLE_H
-#define DEPENDENCYTABLE_H
+#ifndef CPLUSPLUS_DEPENDENCYTABLE_H
+#define CPLUSPLUS_DEPENDENCYTABLE_H
#include <CPlusPlusForwardDeclarations.h>
} // namespace CPlusPlus
-#endif // DEPENDENCYTABLE_H
+#endif // CPLUSPLUS_DEPENDENCYTABLE_H
**
**************************************************************************/
-#include "GenTemplateInstance.h"
+#include "DeprecatedGenTemplateInstance.h"
#include "Overview.h"
#include <Control.h>
class ApplySubstitution
{
public:
- ApplySubstitution(const LookupContext &context, Symbol *symbol, const GenTemplateInstance::Substitution &substitution);
+ ApplySubstitution(Control *control, Symbol *symbol, const DeprecatedGenTemplateInstance::Substitution &substitution);
~ApplySubstitution();
- Control *control() const { return context.control(); }
+ inline Control *control() const { return _control; }
FullySpecifiedType apply(const Name *name);
FullySpecifiedType apply(const FullySpecifiedType &type);
};
public: // attributes
- LookupContext context;
+ Control *_control;
Symbol *symbol;
- GenTemplateInstance::Substitution substitution;
+ DeprecatedGenTemplateInstance::Substitution substitution;
ApplyToType applyToType;
ApplyToName applyToName;
};
-ApplySubstitution::ApplySubstitution(const LookupContext &context, Symbol *symbol,
- const GenTemplateInstance::Substitution &substitution)
- : context(context), symbol(symbol),
+ApplySubstitution::ApplySubstitution(Control *control, Symbol *symbol,
+ const DeprecatedGenTemplateInstance::Substitution &substitution)
+ : _control(control), symbol(symbol),
substitution(substitution),
applyToType(this), applyToName(this)
{ }
} // end of anonymous namespace
-GenTemplateInstance::GenTemplateInstance(const LookupContext &context, const Substitution &substitution)
+DeprecatedGenTemplateInstance::DeprecatedGenTemplateInstance(QSharedPointer<Control> control, const Substitution &substitution)
: _symbol(0),
- _context(context),
+ _control(control),
_substitution(substitution)
{ }
-FullySpecifiedType GenTemplateInstance::operator()(Symbol *symbol)
+FullySpecifiedType DeprecatedGenTemplateInstance::gen(Symbol *symbol)
{
- ApplySubstitution o(_context, symbol, _substitution);
+ ApplySubstitution o(_control.data(), symbol, _substitution);
return o.apply(symbol->type());
}
-Control *GenTemplateInstance::control() const
-{ return _context.control(); }
+FullySpecifiedType DeprecatedGenTemplateInstance::instantiate(const Name *className, Symbol *candidate,
+ QSharedPointer<Control> control)
+{
+ if (className) {
+ if (const TemplateNameId *templId = className->asTemplateNameId()) {
+ if (Class *klass = candidate->enclosingSymbol()->asClass()) {
+ DeprecatedGenTemplateInstance::Substitution subst;
+
+ for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
+ FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
+
+ if (i < klass->templateParameterCount()) {
+ const Name *templArgName = klass->templateParameterAt(i)->name();
+
+ if (templArgName && templArgName->identifier()) {
+ const Identifier *templArgId = templArgName->identifier();
+ subst.append(qMakePair(templArgId, templArgTy));
+ }
+ }
+ }
+
+ DeprecatedGenTemplateInstance inst(control, subst);
+ return inst.gen(candidate);
+ }
+ }
+ }
+
+ return candidate->type();
+}
**
**************************************************************************/
-#ifndef GENTEMPLATEINSTANCE_H
-#define GENTEMPLATEINSTANCE_H
+#ifndef CPLUSPLUS_DEPRECATEDGENTEMPLATEINSTANCE_H
+#define CPLUSPLUS_DEPRECATEDGENTEMPLATEINSTANCE_H
#include <TypeVisitor.h>
#include <NameVisitor.h>
#include <FullySpecifiedType.h>
-#include "LookupContext.h"
-
#include <QtCore/QList>
#include <QtCore/QPair>
+#include <QtCore/QSharedPointer>
namespace CPlusPlus {
-class CPLUSPLUS_EXPORT GenTemplateInstance
+class CPLUSPLUS_EXPORT DeprecatedGenTemplateInstance
{
public:
typedef QList< QPair<const Identifier *, FullySpecifiedType> > Substitution;
public:
- GenTemplateInstance(const LookupContext &context, const Substitution &substitution);
-
- FullySpecifiedType operator()(Symbol *symbol);
+ static FullySpecifiedType instantiate(const Name *className, Symbol *candidate, QSharedPointer<Control> control);
- Control *control() const;
+private:
+ DeprecatedGenTemplateInstance(QSharedPointer<Control> control, const Substitution &substitution);
+ FullySpecifiedType gen(Symbol *symbol);
private:
Symbol *_symbol;
- LookupContext _context;
+ QSharedPointer<Control> _control;
const Substitution _substitution;
};
} // end of namespace CPlusPlus
-#endif // GENTEMPLATEINSTANCE_H
+#endif // CPLUSPLUS_DEPRECATEDGENTEMPLATEINSTANCE_H
#include "ExpressionUnderCursor.h"
#include "SimpleLexer.h"
#include "BackwardsScanner.h"
+#include "TokenCache.h"
#include <Token.h>
#include <QTextCursor>
using namespace CPlusPlus;
-ExpressionUnderCursor::ExpressionUnderCursor()
- : _jumpedComma(false)
+ExpressionUnderCursor::ExpressionUnderCursor(TokenCache *tokenCache)
+ : _tokenCache(tokenCache), _jumpedComma(false)
{ }
ExpressionUnderCursor::~ExpressionUnderCursor()
QString ExpressionUnderCursor::operator()(const QTextCursor &cursor)
{
- BackwardsScanner scanner(cursor);
+ BackwardsScanner scanner(_tokenCache, cursor);
_jumpedComma = false;
int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) const
{
- BackwardsScanner scanner(cursor);
+ BackwardsScanner scanner(_tokenCache, cursor);
int index = scanner.startToken();
**
**************************************************************************/
-#ifndef EXPRESSIONUNDERCURSOR_H
-#define EXPRESSIONUNDERCURSOR_H
+#ifndef CPLUSPLUS_EXPRESSIONUNDERCURSOR_H
+#define CPLUSPLUS_EXPRESSIONUNDERCURSOR_H
#include "CPlusPlusForwardDeclarations.h"
#include <QList>
class BackwardsScanner;
class SimpleToken;
+class TokenCache;
class CPLUSPLUS_EXPORT ExpressionUnderCursor
{
public:
- ExpressionUnderCursor();
+ ExpressionUnderCursor(TokenCache *tokenCache);
~ExpressionUnderCursor();
QString operator()(const QTextCursor &cursor);
bool isAccessToken(const SimpleToken &tk);
private:
+ TokenCache *_tokenCache;
bool _jumpedComma;
};
} // namespace CPlusPlus
-#endif // EXPRESSIONUNDERCURSOR_H
+#endif // CPLUSPLUS_EXPRESSIONUNDERCURSOR_H
**
**************************************************************************/
-#ifndef FASTPREPROCESSOR_H
-#define FASTPREPROCESSOR_H
+#ifndef CPLUSPLUS_FASTPREPROCESSOR_H
+#define CPLUSPLUS_FASTPREPROCESSOR_H
#include "PreprocessorClient.h"
#include "CppDocument.h"
} // end of namespace CPlusPlus
-#endif // FASTPREPROCESSOR_H
+#endif // CPLUSPLUS_FASTPREPROCESSOR_H
**************************************************************************/
#include "FindUsages.h"
-#include "TypeOfExpression.h"
+#include "Overview.h"
#include <Control.h>
#include <Literals.h>
#include <TranslationUnit.h>
#include <QtCore/QDir>
+#include <QtCore/QDebug>
using namespace CPlusPlus;
: ASTVisitor(doc->translationUnit()),
_doc(doc),
_snapshot(snapshot),
+ _context(doc, snapshot),
_source(_doc->source()),
_sem(doc->translationUnit()),
_inSimpleDeclaration(0),
_inQProperty(false)
{
_snapshot.insert(_doc);
+ typeofExpression.init(_doc, _snapshot, _context.bindings());
}
-void FindUsages::setGlobalNamespaceBinding(NamespaceBindingPtr globalNamespaceBinding)
+FindUsages::FindUsages(const LookupContext &context)
+ : ASTVisitor(context.thisDocument()->translationUnit()),
+ _doc(context.thisDocument()),
+ _snapshot(context.snapshot()),
+ _context(context),
+ _source(_doc->source()),
+ _sem(_doc->translationUnit()),
+ _inSimpleDeclaration(0),
+ _inQProperty(false)
{
- _globalNamespaceBinding = globalNamespaceBinding;
+ typeofExpression.init(_doc, _snapshot, _context.bindings());
}
QList<Usage> FindUsages::usages() const
return matchingLine;
}
+Scope *FindUsages::scopeAt(unsigned tokenIndex) const
+{
+ TranslationUnit *unit = _doc->translationUnit();
+ unsigned line, column;
+ unit->getTokenPosition(tokenIndex, &line, &column);
+ return _doc->scopeAt(line, column);
+}
+
void FindUsages::reportResult(unsigned tokenIndex, const QList<Symbol *> &candidates)
{
if (_processed.contains(tokenIndex))
void FindUsages::reportResult(unsigned tokenIndex)
{
- if (_processed.contains(tokenIndex))
+ const Token &tk = tokenAt(tokenIndex);
+ if (tk.generated())
+ return;
+ else if (_processed.contains(tokenIndex))
return;
_processed.insert(tokenIndex);
- const Token &tk = tokenAt(tokenIndex);
const QString lineText = matchingLine(tk);
unsigned line, col;
bool FindUsages::checkCandidates(const QList<Symbol *> &candidates) const
{
- if (Symbol *canonicalSymbol = LookupContext::canonicalSymbol(candidates, _globalNamespaceBinding.data())) {
-
-#if 0
- Symbol *c = candidates.first();
- qDebug() << "*** canonical symbol:" << canonicalSymbol->fileName()
- << canonicalSymbol->line() << canonicalSymbol->column()
- << "candidates:" << candidates.size()
- << c->fileName() << c->line() << c->column();
-#endif
-
- return checkSymbol(canonicalSymbol);
- }
-
- return false;
-}
-
-bool FindUsages::checkScope(Symbol *symbol, Symbol *otherSymbol) const
-{
- if (! (symbol && otherSymbol))
- return false;
-
- else if (symbol->scope() == otherSymbol->scope())
- return true;
-
- else if (symbol->name() && otherSymbol->name()) {
-
- if (! symbol->name()->isEqualTo(otherSymbol->name()))
- return false;
-
- } else if (symbol->name() != otherSymbol->name()) {
- return false;
- }
-
- return checkScope(symbol->enclosingSymbol(), otherSymbol->enclosingSymbol());
-}
-
-bool FindUsages::checkSymbol(Symbol *symbol) const
-{
- if (! symbol) {
- return false;
-
- } else if (symbol == _declSymbol) {
- return true;
-
- } else if (symbol->line() == _declSymbol->line() && symbol->column() == _declSymbol->column()) {
- if (! qstrcmp(symbol->fileName(), _declSymbol->fileName()))
- return true;
-
- } else if (symbol->isForwardClassDeclaration() && (_declSymbol->isClass() ||
- _declSymbol->isForwardClassDeclaration())) {
- return checkScope(symbol, _declSymbol);
-
- } else if (_declSymbol->isForwardClassDeclaration() && (symbol->isClass() ||
- symbol->isForwardClassDeclaration())) {
- return checkScope(symbol, _declSymbol);
+ if (ClassOrNamespace *c = _context.lookupType(_declSymbol)) {
+ for (int i = candidates.size() - 1; i != -1; --i) {
+ Symbol *s = candidates.at(i);
+ if (_context.lookupType(s) == c)
+ return true;
+ }
}
return false;
}
-LookupContext FindUsages::currentContext(AST *ast)
-{
- unsigned line, column;
- getTokenStartPosition(ast->firstToken(), &line, &column);
- Symbol *lastVisibleSymbol = _doc->findSymbolAt(line, column);
-
- if (_inQProperty && lastVisibleSymbol->isClass()) {
- Scope *memberScope = lastVisibleSymbol->asClass()->members();
-
- if (unsigned count = memberScope->symbolCount())
- lastVisibleSymbol = memberScope->symbolAt(count - 1);
- }
-
- if (lastVisibleSymbol && lastVisibleSymbol == _previousContext.symbol())
- return _previousContext;
-
- LookupContext ctx(lastVisibleSymbol, _exprDoc, _doc, _snapshot);
- _previousContext = ctx;
- return _previousContext;
-}
-
void FindUsages::ensureNameIsValid(NameAST *ast)
{
if (ast && ! ast->name)
SimpleNameAST *simple = ast->name->asSimpleName();
if (identifier(simple->identifier_token) == _id) {
- LookupContext context = currentContext(ast);
- const QList<Symbol *> candidates = context.resolve(simple->name);
+ const QList<Symbol *> candidates = _context.lookup(simple->name, scopeAt(simple->identifier_token));
reportResult(simple->identifier_token, candidates);
}
}
const QString expression = _source.mid(begin, end - begin);
// qDebug() << "*** check expression:" << expression;
- TypeOfExpression typeofExpression;
- typeofExpression.setSnapshot(_snapshot);
-
unsigned line, column;
getTokenStartPosition(startToken, &line, &column);
- Symbol *lastVisibleSymbol = _doc->findSymbolAt(line, column);
+ Scope *scope = _doc->scopeAt(line, column);
- const QList<LookupItem> results = typeofExpression(expression, _doc, lastVisibleSymbol,
- TypeOfExpression::Preprocess);
+ const QList<LookupItem> results = typeofExpression(expression, scope,
+ TypeOfExpression::Preprocess);
QList<Symbol *> candidates;
foreach (const LookupItem &r, results) {
- Symbol *lastVisibleSymbol = r.lastVisibleSymbol();
+ Symbol *lastVisibleSymbol = r.declaration();
candidates.append(lastVisibleSymbol);
}
{
const Identifier *id = identifier(ast->identifier_token);
if (id == _id) {
- LookupContext context = currentContext(ast);
- const QList<Symbol *> candidates = context.resolve(control()->nameId(id));
+ const QList<Symbol *> candidates = _context.lookup(control()->nameId(id), scopeAt(ast->identifier_token));
reportResult(ast->identifier_token, candidates);
}
{
const Identifier *id = identifier(ast->identifier_token);
if (id == _id) {
- LookupContext context = currentContext(ast);
- const QList<Symbol *> candidates = context.resolve(ast->name);
+ const QList<Symbol *> candidates = _context.lookup(ast->name, scopeAt(ast->identifier_token));
reportResult(ast->identifier_token, candidates);
}
{
const Identifier *id = identifier(ast->identifier_token);
if (id == _id) {
- LookupContext context = currentContext(ast);
- const QList<Symbol *> candidates = context.resolve(ast->name);
+ const QList<Symbol *> candidates = _context.lookup(ast->name, scopeAt(ast->identifier_token));
reportResult(ast->identifier_token, candidates);
}
bool FindUsages::visit(TemplateIdAST *ast)
{
if (_id == identifier(ast->identifier_token)) {
- LookupContext context = currentContext(ast);
- const QList<Symbol *> candidates = context.resolve(ast->name);
+ const QList<Symbol *> candidates = _context.lookup(ast->name, scopeAt(ast->identifier_token));
reportResult(ast->identifier_token, candidates);
}
if (ast->name) {
const Identifier *id = ast->name->identifier();
if (id == _id) {
- LookupContext context = currentContext(ast);
- const QList<Symbol *> candidates = context.resolve(ast->name);
+ const QList<Symbol *> candidates = _context.lookup(ast->name, scopeAt(ast->firstToken()));
reportResult(ast->firstToken(), candidates);
}
}
void FindUsages::endVisit(QtPropertyDeclarationAST *)
{ _inQProperty = false; }
+
+bool FindUsages::visit(TemplateDeclarationAST *ast)
+{
+ _templateDeclarationStack.append(ast);
+ return true;
+}
+
+void FindUsages::endVisit(TemplateDeclarationAST *)
+{
+ _templateDeclarationStack.takeFirst();
+}
+
+bool FindUsages::visit(TypenameTypeParameterAST *ast)
+{
+ if (NameAST *name = ast->name) {
+ const Identifier *id = name->name->identifier();
+ if (id == _id) {
+ unsigned start = startOfTemplateDeclaration(_templateDeclarationStack.back());
+ const QList<Symbol *> candidates = _context.lookup(name->name, scopeAt(start));
+ reportResult(ast->name->firstToken(), candidates);
+ }
+ }
+ accept(ast->type_id);
+ return false;
+}
+
+bool FindUsages::visit(TemplateTypeParameterAST *ast)
+{
+ if (NameAST *name = ast->name) {
+ const Identifier *id = name->name->identifier();
+ if (id == _id) {
+ unsigned start = startOfTemplateDeclaration(_templateDeclarationStack.back());
+ const QList<Symbol *> candidates = _context.lookup(name->name, scopeAt(start));
+ reportResult(ast->name->firstToken(), candidates);
+ }
+ }
+ accept(ast->type_id);
+ return false;
+}
+
+unsigned FindUsages::startOfTemplateDeclaration(TemplateDeclarationAST *ast) const
+{
+ if (ast->declaration) {
+ if (TemplateDeclarationAST *templ = ast->declaration->asTemplateDeclaration())
+ return startOfTemplateDeclaration(templ);
+
+ return ast->declaration->firstToken();
+ }
+
+ return ast->firstToken();
+}
**
**************************************************************************/
-#ifndef FINDUSAGES_H
-#define FINDUSAGES_H
+#ifndef CPLUSPLUS_FINDUSAGES_H
+#define CPLUSPLUS_FINDUSAGES_H
#include "LookupContext.h"
#include "CppDocument.h"
-#include "CppBindings.h"
#include "Semantic.h"
+#include "TypeOfExpression.h"
#include <ASTVisitor.h>
#include <QtCore/QSet>
{
public:
FindUsages(Document::Ptr doc, const Snapshot &snapshot);
-
- void setGlobalNamespaceBinding(NamespaceBindingPtr globalNamespaceBinding);
+ FindUsages(const LookupContext &context);
void operator()(Symbol *symbol);
using ASTVisitor::endVisit;
QString matchingLine(const Token &tk) const;
+ Scope *scopeAt(unsigned tokenIndex) const;
void reportResult(unsigned tokenIndex, const QList<Symbol *> &candidates);
void reportResult(unsigned tokenIndex);
- bool checkSymbol(Symbol *symbol) const;
bool checkCandidates(const QList<Symbol *> &candidates) const;
- bool checkScope(Symbol *symbol, Symbol *otherSymbol) const;
void checkExpression(unsigned startToken, unsigned endToken);
- LookupContext currentContext(AST *ast);
-
void ensureNameIsValid(NameAST *ast);
virtual bool visit(MemInitializerAST *ast);
virtual bool visit(QtPropertyDeclarationAST *);
virtual void endVisit(QtPropertyDeclarationAST *);
+ virtual bool visit(TemplateDeclarationAST *ast);
+ virtual void endVisit(TemplateDeclarationAST *ast);
+
+ virtual bool visit(TypenameTypeParameterAST *ast);
+ virtual bool visit(TemplateTypeParameterAST *ast);
+
+ unsigned startOfTemplateDeclaration(TemplateDeclarationAST *ast) const;
+
private:
const Identifier *_id;
Symbol *_declSymbol;
Document::Ptr _doc;
Snapshot _snapshot;
+ LookupContext _context;
QByteArray _source;
Document::Ptr _exprDoc;
Semantic _sem;
- NamespaceBindingPtr _globalNamespaceBinding;
QList<PostfixExpressionAST *> _postfixExpressionStack;
QList<QualifiedNameAST *> _qualifiedNameStack;
+ QList<TemplateDeclarationAST *> _templateDeclarationStack;
QList<int> _references;
QList<Usage> _usages;
- LookupContext _previousContext;
int _inSimpleDeclaration;
bool _inQProperty;
QSet<unsigned> _processed;
+ TypeOfExpression typeofExpression;
};
} // end of namespace CPlusPlus
-#endif // FINDUSAGES_H
+#endif // CPLUSPLUS_FINDUSAGES_H
#include "LookupContext.h"
#include "ResolveExpression.h"
#include "Overview.h"
-#include "CppBindings.h"
+#include "DeprecatedGenTemplateInstance.h"
#include <CoreTypes.h>
#include <Symbols.h>
#include <QtDebug>
-uint CPlusPlus::qHash(const CPlusPlus::LookupItem &key)
-{
- const uint h1 = QT_PREPEND_NAMESPACE(qHash)(key.type().type());
- const uint h2 = QT_PREPEND_NAMESPACE(qHash)(key.lastVisibleSymbol());
- return ((h1 << 16) | (h1 >> 16)) ^ h2;
+namespace {
+ const bool debug = ! qgetenv("CPLUSPLUS_LOOKUPCONTEXT_DEBUG").isEmpty();
}
using namespace CPlusPlus;
+static void fullyQualifiedName_helper(Symbol *symbol, QList<const Name *> *names)
+{
+ if (! symbol)
+ return;
+
+ fullyQualifiedName_helper(symbol->enclosingSymbol(), names);
+
+ if (symbol->name()) {
+ if (symbol->isClass() || symbol->isNamespace()) {
+ if (const QualifiedNameId *q = symbol->name()->asQualifiedNameId()) {
+ for (unsigned i = 0; i < q->nameCount(); ++i)
+ names->append(q->nameAt(i));
+
+ } else if (symbol->name()->isNameId() || symbol->name()->isTemplateNameId()) {
+ names->append(symbol->name());
+ }
+ } else if (symbol->isObjCClass() || symbol->isObjCBaseClass() || symbol->isObjCProtocol()
+ || symbol->isObjCForwardClassDeclaration() || symbol->isObjCForwardProtocolDeclaration()) {
+ if (symbol->name())
+ names->append(symbol->name());
+ } else if (symbol->isFunction()) {
+ if (const QualifiedNameId *q = symbol->name()->asQualifiedNameId()) {
+ for (unsigned i = 0; i < q->nameCount() - 1; ++i)
+ names->append(q->nameAt(i));
+ }
+ }
+ }
+}
+
+bool ClassOrNamespace::CompareName::operator()(const Name *name, const Name *other) const
+{
+ Q_ASSERT(name != 0);
+ Q_ASSERT(other != 0);
+
+ const Identifier *id = name->identifier();
+ const Identifier *otherId = other->identifier();
+ return strcmp(id->chars(), otherId->chars()) < 0;
+}
+
/////////////////////////////////////////////////////////////////////
// LookupContext
/////////////////////////////////////////////////////////////////////
-LookupContext::LookupContext(Control *control)
- : _control(control),
- _symbol(0)
+LookupContext::LookupContext()
+ : _control(new Control())
{ }
-LookupContext::LookupContext(Symbol *symbol,
- Document::Ptr expressionDocument,
+LookupContext::LookupContext(Document::Ptr thisDocument,
+ const Snapshot &snapshot)
+ : _expressionDocument(Document::create("<LookupContext>")),
+ _thisDocument(thisDocument),
+ _snapshot(snapshot),
+ _control(new Control())
+{
+}
+
+LookupContext::LookupContext(Document::Ptr expressionDocument,
Document::Ptr thisDocument,
const Snapshot &snapshot)
- : _symbol(symbol),
- _expressionDocument(expressionDocument),
+ : _expressionDocument(expressionDocument),
_thisDocument(thisDocument),
- _snapshot(snapshot)
+ _snapshot(snapshot),
+ _control(new Control())
+{
+}
+
+LookupContext::LookupContext(const LookupContext &other)
+ : _expressionDocument(other._expressionDocument),
+ _thisDocument(other._thisDocument),
+ _snapshot(other._snapshot),
+ _bindings(other._bindings),
+ _control(other._control)
+{ }
+
+LookupContext &LookupContext::operator = (const LookupContext &other)
+{
+ _expressionDocument = other._expressionDocument;
+ _thisDocument = other._thisDocument;
+ _snapshot = other._snapshot;
+ _bindings = other._bindings;
+ _control = other._control;
+ return *this;
+}
+
+QList<const Name *> LookupContext::fullyQualifiedName(Symbol *symbol)
{
- _control = _expressionDocument->control();
- _visibleScopes = buildVisibleScopes();
+ QList<const Name *> names;
+ fullyQualifiedName_helper(symbol, &names);
+ return names;
}
-bool LookupContext::isValid() const
-{ return _control != 0; }
+QSharedPointer<CreateBindings> LookupContext::bindings() const
+{
+ if (! _bindings)
+ _bindings = QSharedPointer<CreateBindings>(new CreateBindings(_thisDocument, _snapshot, control()));
-Control *LookupContext::control() const
-{ return _control; }
+ return _bindings;
+}
-Symbol *LookupContext::symbol() const
-{ return _symbol; }
+void LookupContext::setBindings(QSharedPointer<CreateBindings> bindings)
+{
+ _bindings = bindings;
+}
+
+QSharedPointer<Control> LookupContext::control() const
+{
+ return _control;
+}
Document::Ptr LookupContext::expressionDocument() const
{ return _expressionDocument; }
Snapshot LookupContext::snapshot() const
{ return _snapshot; }
-bool LookupContext::maybeValidSymbol(Symbol *symbol,
- ResolveMode mode,
- const QList<Symbol *> &candidates)
+ClassOrNamespace *LookupContext::globalNamespace() const
{
- if (((mode & ResolveNamespace) && symbol->isNamespace()) ||
- ((mode & ResolveClass) && symbol->isClass()) ||
- ((mode & ResolveObjCClass) && symbol->isObjCClass()) ||
- ((mode & ResolveObjCProtocol) && symbol->isObjCProtocol()) ||
- (mode & ResolveSymbol)) {
- return ! candidates.contains(symbol);
- }
+ return bindings()->globalNamespace();
+}
- return false;
+ClassOrNamespace *LookupContext::lookupType(const Name *name, Scope *scope) const
+{
+ if (ClassOrNamespace *b = bindings()->lookupType(scope->owner()))
+ return b->lookupType(name);
+
+ return 0;
}
-QList<Scope *> LookupContext::resolveNestedNameSpecifier(const QualifiedNameId *q,
- const QList<Scope *> &visibleScopes) const
+ClassOrNamespace *LookupContext::lookupType(Symbol *symbol) const
+{
+ return bindings()->lookupType(symbol);
+}
+
+QList<Symbol *> LookupContext::lookup(const Name *name, Scope *scope) const
{
QList<Symbol *> candidates;
- QList<Scope *> scopes = visibleScopes;
- for (unsigned i = 0; i < q->nameCount() - 1; ++i) {
- const Name *name = q->nameAt(i);
+ if (! name)
+ return candidates;
- candidates = resolveClassOrNamespace(name, scopes);
+ for (; scope; scope = scope->enclosingScope()) {
+ if ((name->isNameId() || name->isTemplateNameId()) && scope->isBlockScope()) {
+ bindings()->lookupInScope(name, scope, &candidates, /*templateId = */ 0);
- if (candidates.isEmpty())
- break;
+ if (! candidates.isEmpty())
+ break; // it's a local.
- scopes.clear();
+ for (unsigned index = 0; index < scope->symbolCount(); ++index) {
+ Symbol *member = scope->symbolAt(index);
- foreach (Symbol *candidate, candidates) {
- ScopedSymbol *scoped = candidate->asScopedSymbol();
- Scope *members = scoped->members();
+ if (UsingNamespaceDirective *u = member->asUsingNamespaceDirective()) {
+ if (Namespace *enclosingNamespace = u->enclosingNamespaceScope()->owner()->asNamespace()) {
+ if (ClassOrNamespace *b = bindings()->lookupType(enclosingNamespace)) {
+ if (ClassOrNamespace *uu = b->lookupType(u->name())) {
+ candidates = uu->find(name);
- if (! scopes.contains(members))
- scopes.append(members);
- }
- }
+ if (! candidates.isEmpty())
+ return candidates;
+ }
+ }
+ }
+ }
+ }
- return scopes;
-}
+ } else if (scope->isFunctionScope()) {
+ Function *fun = scope->owner()->asFunction();
+ bindings()->lookupInScope(name, fun->arguments(), &candidates, /*templateId = */ 0);
-QList<Symbol *> LookupContext::resolveQualifiedNameId(const QualifiedNameId *q,
- const QList<Scope *> &visibleScopes,
- ResolveMode mode) const
-{
- QList<Symbol *> candidates;
+ for (TemplateParameters *it = fun->templateParameters(); it && candidates.isEmpty(); it = it->previous())
+ bindings()->lookupInScope(name, it->scope(), &candidates, /* templateId = */ 0);
- if (true || mode & ResolveClass) {
- for (int i = 0; i < visibleScopes.size(); ++i) {
- Scope *scope = visibleScopes.at(i);
+ if (! candidates.isEmpty())
+ break; // it's an argument or a template parameter.
- for (Symbol *symbol = scope->lookat(q); symbol; symbol = symbol->next()) {
- if (! symbol->name())
- continue;
- else if (! symbol->isClass())
- continue;
+ if (fun->name() && fun->name()->isQualifiedNameId()) {
+ if (ClassOrNamespace *binding = bindings()->lookupType(fun)) {
+ candidates = binding->find(name);
- const QualifiedNameId *qq = symbol->name()->asQualifiedNameId();
+ if (! candidates.isEmpty())
+ return candidates;
+ }
+ }
- if (! qq)
- continue;
- else if (! maybeValidSymbol(symbol, mode, candidates))
- continue;
+ // contunue, and look at the enclosing scope.
- if (! q->unqualifiedNameId()->isEqualTo(qq->unqualifiedNameId()))
- continue;
+ } else if (scope->isObjCMethodScope()) {
+ ObjCMethod *method = scope->owner()->asObjCMethod();
+ bindings()->lookupInScope(name, method->arguments(), &candidates, /*templateId = */ 0);
- else if (qq->nameCount() == q->nameCount()) {
- unsigned j = 0;
+ if (! candidates.isEmpty())
+ break; // it's a formal argument.
- for (; j < q->nameCount(); ++j) {
- const Name *classOrNamespaceName1 = q->nameAt(j);
- const Name *classOrNamespaceName2 = qq->nameAt(j);
+ } else if (scope->isClassScope()) {
+ Class *klass = scope->owner()->asClass();
- if (! classOrNamespaceName1->isEqualTo(classOrNamespaceName2))
- break;
- }
+ for (TemplateParameters *it = klass->templateParameters(); it && candidates.isEmpty(); it = it->previous())
+ bindings()->lookupInScope(name, it->scope(), &candidates, /* templateId = */ 0);
- if (j == q->nameCount())
- candidates.append(symbol);
- }
- }
- }
- }
+ if (! candidates.isEmpty())
+ break; // it's an argument or a template parameter.
- QList<Scope *> scopes;
+ if (ClassOrNamespace *binding = bindings()->lookupType(klass)) {
+ candidates = binding->find(name);
- if (q->nameCount() == 1)
- scopes = visibleScopes; // ### handle global scope lookup
- else
- scopes = resolveNestedNameSpecifier(q, visibleScopes);
+ if (! candidates.isEmpty())
+ return candidates;
+ }
- QList<Scope *> expanded;
- foreach (Scope *scope, scopes) {
- expanded.append(scope);
+ } else if (scope->isNamespaceScope()) {
+ if (ClassOrNamespace *binding = bindings()->lookupType(scope->owner()))
+ candidates = binding->find(name);
- for (unsigned i = 0; i < scope->symbolCount(); ++i) {
- Symbol *member = scope->symbolAt(i);
+ if (! candidates.isEmpty())
+ return candidates;
- if (ScopedSymbol *scopedSymbol = member->asScopedSymbol())
- expandEnumOrAnonymousSymbol(scopedSymbol, &expanded);
+ } else if (scope->isObjCClassScope() || scope->isObjCProtocolScope()) {
+ if (ClassOrNamespace *binding = bindings()->lookupType(scope->owner()))
+ candidates = binding->find(name);
+
+ if (! candidates.isEmpty())
+ return candidates;
}
}
- candidates += resolve(q->unqualifiedNameId(), expanded, mode);
-
return candidates;
}
-QList<Symbol *> LookupContext::resolveOperatorNameId(const OperatorNameId *opId,
- const QList<Scope *> &visibleScopes,
- ResolveMode) const
+ClassOrNamespace::ClassOrNamespace(CreateBindings *factory, ClassOrNamespace *parent)
+ : _factory(factory), _parent(parent), _templateId(0)
{
- QList<Symbol *> candidates;
+}
- for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) {
- Scope *scope = visibleScopes.at(scopeIndex);
+const TemplateNameId *ClassOrNamespace::templateId() const
+{
+ return _templateId;
+}
- for (Symbol *symbol = scope->lookat(opId->kind()); symbol; symbol = symbol->next()) {
- if (! opId->isEqualTo(symbol->name()))
- continue;
+ClassOrNamespace *ClassOrNamespace::parent() const
+{
+ return _parent;
+}
- if (! candidates.contains(symbol))
- candidates.append(symbol);
- }
- }
+QList<ClassOrNamespace *> ClassOrNamespace::usings() const
+{
+ const_cast<ClassOrNamespace *>(this)->flush();
+ return _usings;
+}
- return candidates;
+QList<Enum *> ClassOrNamespace::enums() const
+{
+ const_cast<ClassOrNamespace *>(this)->flush();
+ return _enums;
}
-QList<Symbol *> LookupContext::resolve(const Name *name, const QList<Scope *> &visibleScopes,
- ResolveMode mode) const
+QList<Symbol *> ClassOrNamespace::symbols() const
{
- QList<Symbol *> candidates;
+ if (_templateId && ! _usings.isEmpty())
+ return _usings.first()->symbols(); // ask to the base implementation
- if (!name)
- return candidates; // nothing to do, the symbol is anonymous.
+ const_cast<ClassOrNamespace *>(this)->flush();
+ return _symbols;
+}
- else if (const QualifiedNameId *q = name->asQualifiedNameId())
- return resolveQualifiedNameId(q, visibleScopes, mode);
+ClassOrNamespace *ClassOrNamespace::globalNamespace() const
+{
+ ClassOrNamespace *e = const_cast<ClassOrNamespace *>(this);
- else if (const OperatorNameId *opId = name->asOperatorNameId())
- return resolveOperatorNameId(opId, visibleScopes, mode);
+ do {
+ if (! e->_parent)
+ break;
- else if (const Identifier *id = name->identifier()) {
- for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) {
- Scope *scope = visibleScopes.at(scopeIndex);
+ e = e->_parent;
+ } while (e);
- for (Symbol *symbol = scope->lookat(id); symbol; symbol = symbol->next()) {
- if (! symbol->name())
- continue; // nothing to do, the symbol is anonymous.
+ return e;
+}
- else if (! maybeValidSymbol(symbol, mode, candidates))
- continue; // skip it, we're not looking for this kind of symbols
+QList<Symbol *> ClassOrNamespace::find(const Name *name)
+{
+ return lookup_helper(name, false);
+}
- else if (const Identifier *symbolId = symbol->identifier()) {
- if (! symbolId->isEqualTo(id))
- continue; // skip it, the symbol's id is not compatible with this lookup.
- }
+QList<Symbol *> ClassOrNamespace::lookup(const Name *name)
+{
+ return lookup_helper(name, true);
+}
- if (const QualifiedNameId *q = symbol->name()->asQualifiedNameId()) {
+QList<Symbol *> ClassOrNamespace::lookup_helper(const Name *name, bool searchInEnclosingScope)
+{
+ QList<Symbol *> result;
- if (name->isDestructorNameId() != q->unqualifiedNameId()->isDestructorNameId())
- continue;
+ if (name) {
+ if (const QualifiedNameId *q = name->asQualifiedNameId()) {
+ ClassOrNamespace *binding = this;
- else if (q->nameCount() > 1) {
- const Name *classOrNamespaceName = control()->qualifiedNameId(q->names(),
- q->nameCount() - 1);
+ if (q->isGlobal())
+ binding = globalNamespace();
- if (const Identifier *classOrNamespaceNameId = identifier(classOrNamespaceName)) {
- if (classOrNamespaceNameId->isEqualTo(id))
- continue;
- }
+ if (q->nameCount() == 1)
+ return binding->find(q->unqualifiedNameId());
- const QList<Symbol *> resolvedClassOrNamespace =
- resolveClassOrNamespace(classOrNamespaceName, visibleScopes);
+ binding = binding->lookupType(q->nameAt(0));
- bool good = false;
- foreach (Symbol *classOrNamespace, resolvedClassOrNamespace) {
- ScopedSymbol *scoped = classOrNamespace->asScopedSymbol();
- if (visibleScopes.contains(scoped->members())) {
- good = true;
- break;
- }
- }
+ for (unsigned index = 1; binding && index < q->nameCount() - 1; ++index)
+ binding = binding->findType(q->nameAt(index));
- if (! good)
- continue;
- }
- } else if (symbol->name()->isDestructorNameId() != name->isDestructorNameId()) {
- // ### FIXME: this is wrong!
- continue;
- }
+ if (binding)
+ result = binding->find(q->unqualifiedNameId());
- if (! candidates.contains(symbol))
- candidates.append(symbol);
- }
+ return result;
}
+
+ QSet<ClassOrNamespace *> processed;
+ ClassOrNamespace *binding = this;
+ do {
+ lookup_helper(name, binding, &result, &processed, /*templateId = */ 0);
+ binding = binding->_parent;
+ } while (searchInEnclosingScope && binding);
}
- return candidates;
+ return result;
}
-const Identifier *LookupContext::identifier(const Name *name) const
+void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding,
+ QList<Symbol *> *result,
+ QSet<ClassOrNamespace *> *processed,
+ const TemplateNameId *templateId)
{
- if (name)
- return name->identifier();
+ if (binding && ! processed->contains(binding)) {
+ processed->insert(binding);
- return 0;
-}
+ const Identifier *nameId = name->identifier();
-void LookupContext::buildVisibleScopes_helper(Document::Ptr doc, QList<Scope *> *scopes,
- QSet<QString> *processed)
-{
- if (doc && ! processed->contains(doc->fileName())) {
- processed->insert(doc->fileName());
+ foreach (Symbol *s, binding->symbols()) {
+ if (ScopedSymbol *scoped = s->asScopedSymbol()) {
+ if (Class *klass = scoped->asClass()) {
+ if (const Identifier *id = klass->identifier()) {
+ if (nameId && nameId->isEqualTo(id))
+ result->append(klass);
+ }
+ }
+ _factory->lookupInScope(name, scoped->members(), result, templateId);
+ }
+ }
- if (doc->globalSymbolCount())
- scopes->append(doc->globalSymbols());
+ foreach (Enum *e, binding->enums())
+ _factory->lookupInScope(name, e->members(), result, templateId);
- foreach (const Document::Include &incl, doc->includes()) {
- buildVisibleScopes_helper(_snapshot.document(incl.fileName()),
- scopes, processed);
- }
+ foreach (ClassOrNamespace *u, binding->usings())
+ lookup_helper(name, u, result, processed, binding->_templateId);
}
}
-QList<Scope *> LookupContext::buildVisibleScopes()
+void CreateBindings::lookupInScope(const Name *name, Scope *scope,
+ QList<Symbol *> *result,
+ const TemplateNameId *templateId)
{
- QList<Scope *> scopes;
-
- if (_symbol) {
- Scope *scope = _symbol->scope();
+ Q_UNUSED(templateId);
- if (Function *fun = _symbol->asFunction())
- scope = fun->members(); // handle ctor initializers.
+ if (! name) {
+ return;
- for (; scope; scope = scope->enclosingScope()) {
- if (scope == _thisDocument->globalSymbols())
- break;
+ } else if (const OperatorNameId *op = name->asOperatorNameId()) {
+ for (Symbol *s = scope->lookat(op->kind()); s; s = s->next()) {
+ if (! s->name())
+ continue;
+ else if (! s->name()->isEqualTo(op))
+ continue;
- scopes.append(scope);
+ result->append(s);
}
- }
- QSet<QString> processed;
- buildVisibleScopes_helper(_thisDocument, &scopes, &processed);
+ } else if (const Identifier *id = name->identifier()) {
+ for (Symbol *s = scope->lookat(id); s; s = s->next()) {
+ if (! id->isEqualTo(s->identifier()))
+ continue;
+ else if (s->name()->isQualifiedNameId())
+ continue; // skip qualified ids.
- while (true) {
- QList<Scope *> expandedScopes;
- expand(scopes, &expandedScopes);
+#if 0
+ if (templateId && (s->isDeclaration() || s->isFunction())) {
- if (expandedScopes.size() == scopes.size())
- return expandedScopes;
+ FullySpecifiedType ty = DeprecatedGenTemplateInstance::instantiate(templateId, s, _control);
- scopes = expandedScopes;
- }
+ if (debug) {
+ Overview oo;
+ oo.setShowFunctionSignatures(true);
+ oo.setShowReturnTypes(true);
+ qDebug() << "instantiate:" << oo(s->type(), s->name()) << "using:" << oo(templateId) << oo(ty);
+ }
- return scopes;
+ if (Declaration *decl = s->asDeclaration()) {
+ Declaration *d = _control->newDeclaration(0, 0);
+ d->copy(decl);
+ d->setType(ty);
+ result->append(d);
+ continue;
+ } else if (Function *fun = s->asFunction()) {
+ Function *d = ty->asFunctionType();
+ d->copy(fun);
+ result->append(d);
+ continue;
+ }
+ }
+#endif
+
+ result->append(s);
+ }
+
+ }
}
-QList<Scope *> LookupContext::visibleScopes(const LookupItem &result) const
-{ return visibleScopes(result.lastVisibleSymbol()); }
+ClassOrNamespace *ClassOrNamespace::lookupType(const Name *name)
+{
+ if (! name)
+ return 0;
-QList<Scope *> LookupContext::visibleScopes(Symbol *symbol) const
+ QSet<ClassOrNamespace *> processed;
+ return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ true);
+}
+
+ClassOrNamespace *ClassOrNamespace::findType(const Name *name)
{
- QList<Scope *> scopes;
- if (symbol) {
- for (Scope *scope = symbol->scope(); scope; scope = scope->enclosingScope())
- scopes.append(scope);
- }
- scopes += visibleScopes();
- scopes = expand(scopes);
- return scopes;
+ QSet<ClassOrNamespace *> processed;
+ return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ false);
}
-void LookupContext::expandEnumOrAnonymousSymbol(ScopedSymbol *scopedSymbol,
- QList<Scope *> *expandedScopes) const
+ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name,
+ QSet<ClassOrNamespace *> *processed,
+ bool searchInEnclosingScope)
{
- if (! scopedSymbol || expandedScopes->contains(scopedSymbol->members()))
- return;
+ if (const QualifiedNameId *q = name->asQualifiedNameId()) {
+ ClassOrNamespace *e = this;
+
+ if (q->isGlobal())
+ e = globalNamespace();
+
+ e = e->lookupType(q->nameAt(0));
+
+ for (unsigned index = 1; e && index < q->nameCount(); ++index)
+ e = e->findType(q->nameAt(index));
- Scope *members = scopedSymbol->members();
+ return e;
- if (scopedSymbol->isEnum())
- expandedScopes->append(members);
- else if (! scopedSymbol->name() && (scopedSymbol->isClass() || scopedSymbol->isNamespace())) {
- // anonymous class or namespace
+ } else if (! processed->contains(this)) {
+ processed->insert(this);
- expandedScopes->append(members);
+ if (name->isNameId() || name->isTemplateNameId()) {
+ flush();
- for (unsigned i = 0; i < members->symbolCount(); ++i) {
- Symbol *member = members->symbolAt(i);
+ foreach (Symbol *s, symbols()) {
+ if (Class *klass = s->asClass()) {
+ if (klass->identifier() && klass->identifier()->isEqualTo(name->identifier()))
+ return this;
+ }
+ }
+
+ if (ClassOrNamespace *e = nestedType(name))
+ return e;
- if (ScopedSymbol *nested = member->asScopedSymbol()) {
- expandEnumOrAnonymousSymbol(nested, expandedScopes);
+ else if (_templateId) {
+ if (_usings.size() == 1) {
+ ClassOrNamespace *delegate = _usings.first();
+
+ if (ClassOrNamespace *r = delegate->lookupType_helper(name, processed, /*searchInEnclosingScope = */ true))
+ return r;
+ } else {
+ if (debug)
+ qWarning() << "expected one using declaration. Number of using declarations is:" << _usings.size();
+ }
+ }
+
+ foreach (ClassOrNamespace *u, usings()) {
+ if (ClassOrNamespace *r = u->lookupType_helper(name, processed, /*searchInEnclosingScope =*/ false))
+ return r;
}
}
+
+ if (_parent && searchInEnclosingScope)
+ return _parent->lookupType_helper(name, processed, searchInEnclosingScope);
}
+
+ return 0;
}
-QList<Scope *> LookupContext::expand(const QList<Scope *> &scopes) const
+ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name) const
{
- QList<Scope *> expanded;
- expand(scopes, &expanded);
- return expanded;
+ Q_ASSERT(name != 0);
+ Q_ASSERT(name->isNameId() || name->isTemplateNameId());
+
+ const_cast<ClassOrNamespace *>(this)->flush();
+
+ Table::const_iterator it = _classOrNamespaces.find(name);
+
+ if (it == _classOrNamespaces.end())
+ return 0;
+
+ ClassOrNamespace *c = it->second;
+
+ if (const TemplateNameId *templId = name->asTemplateNameId()) {
+ ClassOrNamespace *i = _factory->allocClassOrNamespace(c);
+ i->_templateId = templId;
+ i->_usings.append(c);
+ c->_instantiations.append(i);
+ return i;
+ }
+
+ return c;
}
-void LookupContext::expand(const QList<Scope *> &scopes, QList<Scope *> *expandedScopes) const
+void ClassOrNamespace::flush()
{
- for (int i = 0; i < scopes.size(); ++i) {
- expand(scopes.at(i), scopes, expandedScopes);
+ if (! _todo.isEmpty()) {
+ const QList<Symbol *> todo = _todo;
+ _todo.clear();
+
+ foreach (Symbol *member, todo)
+ _factory->process(member, this);
}
}
-void LookupContext::expandNamespace(Namespace *ns,
- const QList<Scope *> &visibleScopes,
- QList<Scope *> *expandedScopes) const
+void ClassOrNamespace::addSymbol(Symbol *symbol)
{
- //qDebug() << "*** expand namespace:" << ns->fileName() << ns->line() << ns->column();
+ _symbols.append(symbol);
+}
- if (Scope *encl = ns->enclosingNamespaceScope())
- expand(encl, visibleScopes, expandedScopes);
+void ClassOrNamespace::addTodo(Symbol *symbol)
+{
+ _todo.append(symbol);
+}
- if (const Name *nsName = ns->name()) {
- const QList<Symbol *> namespaceList = resolveNamespace(nsName, visibleScopes);
- foreach (Symbol *otherNs, namespaceList) {
- if (otherNs == ns)
- continue;
- expand(otherNs->asNamespace()->members(), visibleScopes, expandedScopes);
- }
- }
+void ClassOrNamespace::addEnum(Enum *e)
+{
+ _enums.append(e);
+}
- for (unsigned i = 0; i < ns->memberCount(); ++i) { // ### make me fast
- Symbol *symbol = ns->memberAt(i);
- if (Namespace *otherNs = symbol->asNamespace()) {
- if (! otherNs->name()) {
- expand(otherNs->members(), visibleScopes, expandedScopes);
- }
- } else if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
- const QList<Symbol *> candidates = resolveNamespace(u->name(), visibleScopes);
- for (int j = 0; j < candidates.size(); ++j) {
- expand(candidates.at(j)->asNamespace()->members(),
- visibleScopes, expandedScopes);
- }
- } else if (Enum *e = symbol->asEnum()) {
- expand(e->members(), visibleScopes, expandedScopes);
- }
- }
+void ClassOrNamespace::addUsing(ClassOrNamespace *u)
+{
+ _usings.append(u);
}
-void LookupContext::expandClass(Class *klass,
- const QList<Scope *> &visibleScopes,
- QList<Scope *> *expandedScopes) const
+void ClassOrNamespace::addNestedType(const Name *alias, ClassOrNamespace *e)
{
- for (TemplateParameters *params = klass->templateParameters(); params; params = params->previous())
- expand(params->scope(), visibleScopes, expandedScopes);
+ _classOrNamespaces[alias] = e;
+}
- for (unsigned i = 0; i < klass->memberCount(); ++i) {
- Symbol *symbol = klass->memberAt(i);
- if (Class *nestedClass = symbol->asClass()) {
- if (! nestedClass->name()) {
- expand(nestedClass->members(), visibleScopes, expandedScopes);
- }
- } else if (Enum *e = symbol->asEnum()) {
- expand(e->members(), visibleScopes, expandedScopes);
- }
- }
+ClassOrNamespace *ClassOrNamespace::findOrCreateType(const Name *name)
+{
+ if (! name)
+ return this;
- if (klass->baseClassCount()) {
- QList<Scope *> classVisibleScopes = visibleScopes;
- for (Scope *scope = klass->scope(); scope; scope = scope->enclosingScope()) {
- if (scope->isNamespaceScope()) {
- Namespace *enclosingNamespace = scope->owner()->asNamespace();
- if (enclosingNamespace->name()) {
- const QList<Symbol *> nsList = resolveNamespace(enclosingNamespace->name(),
- visibleScopes);
- foreach (Symbol *ns, nsList) {
- expand(ns->asNamespace()->members(), classVisibleScopes,
- &classVisibleScopes);
- }
- }
- }
- }
+ if (const QualifiedNameId *q = name->asQualifiedNameId()) {
+ ClassOrNamespace *e = this;
- for (unsigned i = 0; i < klass->baseClassCount(); ++i) {
- BaseClass *baseClass = klass->baseClassAt(i);
- const Name *baseClassName = baseClass->name();
- const QList<Symbol *> baseClassCandidates = resolveClass(baseClassName,
- classVisibleScopes);
+ for (unsigned i = 0; e && i < q->nameCount(); ++i)
+ e = e->findOrCreateType(q->nameAt(i));
- for (int j = 0; j < baseClassCandidates.size(); ++j) {
- if (Class *baseClassSymbol = baseClassCandidates.at(j)->asClass())
- expand(baseClassSymbol->members(), visibleScopes, expandedScopes);
- }
+ return e;
+
+ } else if (name->isNameId() || name->isTemplateNameId()) {
+ ClassOrNamespace *e = nestedType(name);
+
+ if (! e) {
+ e = _factory->allocClassOrNamespace(this);
+ _classOrNamespaces[name] = e;
}
+
+ return e;
}
+
+ return 0;
}
-void LookupContext::expandBlock(Block *blockSymbol,
- const QList<Scope *> &visibleScopes,
- QList<Scope *> *expandedScopes) const
+CreateBindings::CreateBindings(Document::Ptr thisDocument, const Snapshot &snapshot, QSharedPointer<Control> control)
+ : _snapshot(snapshot), _control(control)
{
- for (unsigned i = 0; i < blockSymbol->memberCount(); ++i) {
- Symbol *symbol = blockSymbol->memberAt(i);
- if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
- const QList<Symbol *> candidates = resolveNamespace(u->name(),
- visibleScopes);
- for (int j = 0; j < candidates.size(); ++j) {
- expand(candidates.at(j)->asNamespace()->members(),
- visibleScopes, expandedScopes);
- }
- }
+ _globalNamespace = allocClassOrNamespace(/*parent = */ 0);
+ _currentClassOrNamespace = _globalNamespace;
- }
+ process(thisDocument);
}
-void LookupContext::expandFunction(Function *function,
- const QList<Scope *> &visibleScopes,
- QList<Scope *> *expandedScopes) const
+CreateBindings::~CreateBindings()
{
- for (TemplateParameters *params = function->templateParameters(); params; params = params->previous())
- expand(params->scope(), visibleScopes, expandedScopes);
-
- if (! expandedScopes->contains(function->arguments()))
- expandedScopes->append(function->arguments());
+ qDeleteAll(_entities);
+}
- if (const QualifiedNameId *q = function->name()->asQualifiedNameId()) {
- const Name *nestedNameSpec = 0;
- if (q->nameCount() == 1)
- nestedNameSpec = q->nameAt(0);
- else
- nestedNameSpec = control()->qualifiedNameId(q->names(), q->nameCount() - 1,
- q->isGlobal());
- const QList<Symbol *> candidates = resolveClassOrNamespace(nestedNameSpec, visibleScopes);
- for (int j = 0; j < candidates.size(); ++j) {
- if (ScopedSymbol *scopedSymbol = candidates.at(j)->asScopedSymbol())
- expand(scopedSymbol->members(), visibleScopes, expandedScopes);
- }
- }
+ClassOrNamespace *CreateBindings::switchCurrentClassOrNamespace(ClassOrNamespace *classOrNamespace)
+{
+ ClassOrNamespace *previous = _currentClassOrNamespace;
+ _currentClassOrNamespace = classOrNamespace;
+ return previous;
}
-void LookupContext::expandObjCMethod(ObjCMethod *method,
- const QList<Scope *> &,
- QList<Scope *> *expandedScopes) const
+ClassOrNamespace *CreateBindings::globalNamespace() const
{
- if (! expandedScopes->contains(method->arguments()))
- expandedScopes->append(method->arguments());
+ return _globalNamespace;
}
-void LookupContext::expandObjCClass(ObjCClass *klass,
- const QList<Scope *> &visibleScopes,
- QList<Scope *> *expandedScopes) const
+ClassOrNamespace *CreateBindings::lookupType(Symbol *symbol)
{
- {// expand other @interfaces, @implementations and categories for this class:
- const QList<Symbol *> classList = resolveObjCClass(klass->name(), visibleScopes);
- foreach (Symbol *otherClass, classList) {
- if (otherClass == klass)
- continue;
- expand(otherClass->asObjCClass()->members(), visibleScopes, expandedScopes);
- }
- }
+ const QList<const Name *> names = LookupContext::fullyQualifiedName(symbol);
- // expand definitions in the currect class:
- for (unsigned i = 0; i < klass->memberCount(); ++i) {
- Symbol *symbol = klass->memberAt(i);
- if (Class *nestedClass = symbol->asClass()) {
- if (! nestedClass->name()) {
- expand(nestedClass->members(), visibleScopes, expandedScopes);
- }
- } else if (Enum *e = symbol->asEnum()) {
- expand(e->members(), visibleScopes, expandedScopes);
- }
- }
+ if (names.isEmpty())
+ return _globalNamespace;
- // expand the base class:
- if (ObjCBaseClass *baseClass = klass->baseClass()) {
- const Name *baseClassName = baseClass->name();
- const QList<Symbol *> baseClassCandidates = resolveObjCClass(baseClassName,
- visibleScopes);
+ ClassOrNamespace *b = _globalNamespace->lookupType(names.at(0));
- for (int j = 0; j < baseClassCandidates.size(); ++j) {
- if (ObjCClass *baseClassSymbol = baseClassCandidates.at(j)->asObjCClass())
- expand(baseClassSymbol->members(), visibleScopes, expandedScopes);
- }
- }
+ for (int i = 1; b && i < names.size(); ++i)
+ b = b->findType(names.at(i));
- // expand the protocols:
- for (unsigned i = 0; i < klass->protocolCount(); ++i) {
- const Name *protocolName = klass->protocolAt(i)->name();
- const QList<Symbol *> protocolCandidates = resolveObjCProtocol(protocolName, visibleScopes);
- for (int j = 0; j < protocolCandidates.size(); ++j) {
- if (ObjCProtocol *protocolSymbol = protocolCandidates.at(j)->asObjCProtocol())
- expandObjCProtocol(protocolSymbol, visibleScopes, expandedScopes);
- }
- }
+ return b;
}
-void LookupContext::expandObjCProtocol(ObjCProtocol *protocol, const QList<Scope *> &visibleScopes, QList<Scope *> *expandedScopes) const
+void CreateBindings::process(Symbol *s, ClassOrNamespace *classOrNamespace)
{
- // First expand the protocol itself
- expand(protocol->members(), visibleScopes, expandedScopes);
+ ClassOrNamespace *previous = switchCurrentClassOrNamespace(classOrNamespace);
+ accept(s);
+ (void) switchCurrentClassOrNamespace(previous);
+}
- // Then do the same for any incorporated protocol
- for (unsigned i = 0; i < protocol->protocolCount(); ++i) {
- ObjCBaseProtocol *baseProtocol = protocol->protocolAt(i);
- const QList<Symbol *> protocolList = resolveObjCProtocol(baseProtocol->name(), visibleScopes);
- foreach (Symbol *symbol, protocolList)
- if (ObjCProtocol *protocolSymbol = symbol->asObjCProtocol())
- expandObjCProtocol(protocolSymbol, visibleScopes, expandedScopes);
- }
+void CreateBindings::process(Symbol *symbol)
+{
+ _currentClassOrNamespace->addTodo(symbol);
}
-void LookupContext::expand(Scope *scope,
- const QList<Scope *> &visibleScopes,
- QList<Scope *> *expandedScopes) const
+QSharedPointer<Control> CreateBindings::control() const
{
- if (expandedScopes->contains(scope))
- return;
+ return _control;
+}
- expandedScopes->append(scope);
-
- if (Namespace *ns = scope->owner()->asNamespace()) {
- expandNamespace(ns, visibleScopes, expandedScopes);
- } else if (Class *klass = scope->owner()->asClass()) {
- expandClass(klass, visibleScopes, expandedScopes);
- } else if (Block *block = scope->owner()->asBlock()) {
- expandBlock(block, visibleScopes, expandedScopes);
- } else if (Function *fun = scope->owner()->asFunction()) {
- expandFunction(fun, visibleScopes, expandedScopes);
- } else if (ObjCMethod *meth = scope->owner()->asObjCMethod()) {
- expandObjCMethod(meth, visibleScopes, expandedScopes);
- } else if (ObjCClass *objcKlass = scope->owner()->asObjCClass()) {
- expandObjCClass(objcKlass, visibleScopes, expandedScopes);
- }
+ClassOrNamespace *CreateBindings::allocClassOrNamespace(ClassOrNamespace *parent)
+{
+ ClassOrNamespace *e = new ClassOrNamespace(this, parent);
+ _entities.append(e);
+ return e;
}
-static void visibleClassBindings_helper(ClassBinding *classBinding,
- QList<ClassBinding *> *allClassBindings,
- QSet<ClassBinding *> *processed)
+void CreateBindings::process(Document::Ptr doc)
{
- if (! classBinding)
+ if (! doc)
return;
- else if (processed->contains(classBinding))
- return;
+ else if (Namespace *globalNamespace = doc->globalNamespace()) {
+ if (! _processed.contains(globalNamespace)) {
+ _processed.insert(globalNamespace);
- processed->insert(classBinding);
+ foreach (const Document::Include &i, doc->includes()) {
+ if (Document::Ptr incl = _snapshot.document(i.fileName()))
+ process(incl);
+ }
- foreach (ClassBinding *baseClassBinding, classBinding->baseClassBindings)
- visibleClassBindings_helper(baseClassBinding, allClassBindings, processed);
+ accept(globalNamespace);
+ }
+ }
+}
- allClassBindings->append(classBinding);
+ClassOrNamespace *CreateBindings::enterClassOrNamespaceBinding(Symbol *symbol)
+{
+ ClassOrNamespace *entity = _currentClassOrNamespace->findOrCreateType(symbol->name());
+ entity->addSymbol(symbol);
+
+ return switchCurrentClassOrNamespace(entity);
}
-static QList<ClassBinding *> visibleClassBindings(Symbol *symbol, NamespaceBinding *globalNamespace)
+ClassOrNamespace *CreateBindings::enterGlobalClassOrNamespace(Symbol *symbol)
{
- QList<ClassBinding *> classBindings;
+ ClassOrNamespace *entity = _globalNamespace->findOrCreateType(symbol->name());
+ entity->addSymbol(symbol);
- if (! symbol)
- return classBindings;
+ return switchCurrentClassOrNamespace(entity);
+}
- else if (Class *klass = symbol->asClass()) {
- QSet<ClassBinding *> processed;
+bool CreateBindings::visit(Namespace *ns)
+{
+ ClassOrNamespace *previous = enterClassOrNamespaceBinding(ns);
- visibleClassBindings_helper(NamespaceBinding::find(klass, globalNamespace),
- &classBindings, &processed);
- }
+ for (unsigned i = 0; i < ns->memberCount(); ++i)
+ process(ns->memberAt(i));
- return classBindings;
+ _currentClassOrNamespace = previous;
+ return false;
}
-Symbol *LookupContext::canonicalSymbol(Symbol *symbol,
- NamespaceBinding *globalNamespace)
+bool CreateBindings::visit(Class *klass)
{
- Symbol *canonicalSymbol = LookupContext::canonicalSymbol(symbol);
- if (! canonicalSymbol)
- return 0;
+ ClassOrNamespace *previous = _currentClassOrNamespace;
+ ClassOrNamespace *binding = 0;
- if (const Identifier *symbolId = canonicalSymbol->identifier()) {
- if (symbolId && canonicalSymbol->type()->isFunctionType()) {
- Class *enclosingClass = canonicalSymbol->scope()->owner()->asClass();
- const QList<ClassBinding *> classBindings = visibleClassBindings(enclosingClass, globalNamespace);
+ if (klass->name() && klass->name()->isQualifiedNameId())
+ binding = _currentClassOrNamespace->lookupType(klass->name());
- foreach (ClassBinding *baseClassBinding, classBindings) {
- if (! baseClassBinding)
- continue;
+ if (! binding)
+ binding = _currentClassOrNamespace->findOrCreateType(klass->name());
- foreach (Class *baseClass, baseClassBinding->symbols) {
- if (! baseClass)
- continue;
+ _currentClassOrNamespace = binding;
+ _currentClassOrNamespace->addSymbol(klass);
- for (Symbol *c = baseClass->members()->lookat(symbolId); c; c = c->next()) {
- if (! symbolId->isEqualTo(c->identifier()))
- continue;
- else if (Function *f = c->type()->asFunctionType()) {
- if (f->isVirtual())
- return LookupContext::canonicalSymbol(f);
- }
- }
+ for (unsigned i = 0; i < klass->baseClassCount(); ++i)
+ process(klass->baseClassAt(i));
+
+ for (unsigned i = 0; i < klass->memberCount(); ++i)
+ process(klass->memberAt(i));
+
+ _currentClassOrNamespace = previous;
+ return false;
+}
+
+bool CreateBindings::visit(ForwardClassDeclaration *klass)
+{
+ if (! klass->isFriend()) {
+ ClassOrNamespace *previous = enterClassOrNamespaceBinding(klass);
+ _currentClassOrNamespace = previous;
+ }
+
+ return false;
+}
+
+bool CreateBindings::visit(Enum *e)
+{
+ _currentClassOrNamespace->addEnum(e);
+ return false;
+}
+
+bool CreateBindings::visit(Declaration *decl)
+{
+ if (decl->isTypedef()) {
+ FullySpecifiedType ty = decl->type();
+ const Identifier *typedefId = decl->identifier();
+
+ if (typedefId && ! (ty.isConst() || ty.isVolatile())) {
+ if (const NamedType *namedTy = ty->asNamedType()) {
+ if (ClassOrNamespace *e = _currentClassOrNamespace->lookupType(namedTy->name())) {
+ _currentClassOrNamespace->addNestedType(decl->name(), e);
+ } else if (false) {
+ Overview oo;
+ qDebug() << "found entity not found for" << oo(namedTy->name());
+ }
+ } else if (Class *klass = ty->asClassType()) {
+ if (const NameId *nameId = decl->name()->asNameId()) {
+ ClassOrNamespace *binding = _currentClassOrNamespace->findOrCreateType(nameId);
+ binding->addSymbol(klass);
}
}
}
}
- return canonicalSymbol;
+ return false;
}
-Symbol *LookupContext::canonicalSymbol(const QList<Symbol *> &candidates,
- NamespaceBinding *globalNamespaceBinding)
+bool CreateBindings::visit(Function *)
{
- if (candidates.isEmpty())
- return 0;
-
- return canonicalSymbol(candidates.first(), globalNamespaceBinding);
+ return false;
}
-Symbol *LookupContext::canonicalSymbol(const QList<LookupItem> &results,
- NamespaceBinding *globalNamespaceBinding)
+bool CreateBindings::visit(BaseClass *b)
{
- QList<Symbol *> candidates;
-
- foreach (const LookupItem &result, results)
- candidates.append(result.lastVisibleSymbol()); // ### not exactly.
+ if (ClassOrNamespace *base = _currentClassOrNamespace->lookupType(b->name())) {
+ _currentClassOrNamespace->addUsing(base);
+ } else if (false) {
+ Overview oo;
+ qDebug() << "no entity for:" << oo(b->name());
+ }
+ return false;
+}
- return canonicalSymbol(candidates, globalNamespaceBinding);
+bool CreateBindings::visit(UsingDeclaration *u)
+{
+ if (u->name()) {
+ if (const QualifiedNameId *q = u->name()->asQualifiedNameId()) {
+ if (const NameId *unqualifiedId = q->unqualifiedNameId()->asNameId()) {
+ if (ClassOrNamespace *delegate = _currentClassOrNamespace->lookupType(q)) {
+ ClassOrNamespace *b = _currentClassOrNamespace->findOrCreateType(unqualifiedId);
+ b->addUsing(delegate);
+ }
+ }
+ }
+ }
+ return false;
}
+bool CreateBindings::visit(UsingNamespaceDirective *u)
+{
+ if (ClassOrNamespace *e = _currentClassOrNamespace->lookupType(u->name())) {
+ _currentClassOrNamespace->addUsing(e);
+ } else if (false) {
+ Overview oo;
+ qDebug() << "no entity for namespace:" << oo(u->name());
+ }
+ return false;
+}
-Symbol *LookupContext::canonicalSymbol(Symbol *symbol)
+bool CreateBindings::visit(NamespaceAlias *a)
{
- Symbol *canonical = symbol;
- Class *canonicalClass = 0;
- ObjCClass *canonicalObjCClass = 0;
- ObjCProtocol *canonicalObjCProto = 0;
+ if (! a->identifier()) {
+ return false;
- for (; symbol; symbol = symbol->next()) {
- if (symbol->identifier() == canonical->identifier()) {
- canonical = symbol;
+ } else if (ClassOrNamespace *e = _currentClassOrNamespace->lookupType(a->namespaceName())) {
+ if (a->name()->isNameId() || a->name()->isTemplateNameId())
+ _currentClassOrNamespace->addNestedType(a->name(), e);
- if (Class *klass = symbol->asClass())
- canonicalClass = klass;
- else if (ObjCClass *clazz = symbol->asObjCClass())
- canonicalObjCClass = clazz;
- else if (ObjCProtocol *proto = symbol->asObjCProtocol())
- canonicalObjCProto = proto;
- }
+ } else if (false) {
+ Overview oo;
+ qDebug() << "no entity for namespace:" << oo(a->namespaceName());
}
- if (canonicalClass) {
- Q_ASSERT(canonical != 0);
+ return false;
+}
+
+bool CreateBindings::visit(ObjCClass *klass)
+{
+ ClassOrNamespace *previous = enterGlobalClassOrNamespace(klass);
+
+ process(klass->baseClass());
+
+ for (unsigned i = 0; i < klass->protocolCount(); ++i)
+ process(klass->protocolAt(i));
- if (canonical->isForwardClassDeclaration())
- return canonicalClass; // prefer class declarations when available.
- } else if (canonicalObjCClass) {
- Q_ASSERT(canonical != 0);
+ for (unsigned i = 0; i < klass->memberCount(); ++i)
+ process(klass->memberAt(i));
- if (canonical->isObjCForwardClassDeclaration())
- return canonicalObjCClass;
- } else if (canonicalObjCProto) {
- Q_ASSERT(canonical != 0);
+ _currentClassOrNamespace = previous;
+ return false;
+}
- if (canonical->isObjCForwardProtocolDeclaration())
- return canonicalObjCProto;
+bool CreateBindings::visit(ObjCBaseClass *b)
+{
+ if (ClassOrNamespace *base = _globalNamespace->lookupType(b->name())) {
+ _currentClassOrNamespace->addUsing(base);
+ } else if (false) {
+ Overview oo;
+ qDebug() << "no entity for:" << oo(b->name());
}
+ return false;
+}
+
+bool CreateBindings::visit(ObjCForwardClassDeclaration *klass)
+{
+ ClassOrNamespace *previous = enterGlobalClassOrNamespace(klass);
+ _currentClassOrNamespace = previous;
+ return false;
+}
+
+bool CreateBindings::visit(ObjCProtocol *proto)
+{
+ ClassOrNamespace *previous = enterGlobalClassOrNamespace(proto);
- if (canonical && canonical->scope()->isClassScope()) {
- Class *enclosingClass = canonical->scope()->owner()->asClass();
+ for (unsigned i = 0; i < proto->protocolCount(); ++i)
+ process(proto->protocolAt(i));
+
+ for (unsigned i = 0; i < proto->memberCount(); ++i)
+ process(proto->memberAt(i));
+
+ _currentClassOrNamespace = previous;
+ return false;
+}
- if (enclosingClass->identifier() == canonical->identifier())
- return enclosingClass;
+bool CreateBindings::visit(ObjCBaseProtocol *b)
+{
+ if (ClassOrNamespace *base = _globalNamespace->lookupType(b->name())) {
+ _currentClassOrNamespace->addUsing(base);
+ } else if (false) {
+ Overview oo;
+ qDebug() << "no entity for:" << oo(b->name());
}
+ return false;
+}
- return canonical;
+bool CreateBindings::visit(ObjCForwardProtocolDeclaration *proto)
+{
+ ClassOrNamespace *previous = enterGlobalClassOrNamespace(proto);
+ _currentClassOrNamespace = previous;
+ return false;
+}
+
+bool CreateBindings::visit(ObjCMethod *)
+{
+ return false;
}
#define CPLUSPLUS_LOOKUPCONTEXT_H
#include "CppDocument.h"
+#include "LookupItem.h"
#include <FullySpecifiedType.h>
+#include <Type.h>
+#include <SymbolVisitor.h>
+#include <Control.h>
+#include <QtCore/QSet>
+#include <map>
+#include <functional>
namespace CPlusPlus {
-class CPLUSPLUS_EXPORT LookupItem
-{
-public:
- LookupItem()
- : _lastVisibleSymbol(0) {}
-
- LookupItem(const FullySpecifiedType &type, Symbol *lastVisibleSymbol)
- : _type(type), _lastVisibleSymbol(lastVisibleSymbol) {}
-
- FullySpecifiedType type() const { return _type; }
- void setType(const FullySpecifiedType &type) { _type = type; }
-
- Symbol *lastVisibleSymbol() const { return _lastVisibleSymbol; }
- void setLastVisibleSymbol(Symbol *symbol) { _lastVisibleSymbol = symbol; }
-
- bool operator == (const LookupItem &other) const
- {
- if (_type == other._type)
- return _lastVisibleSymbol == other._lastVisibleSymbol;
-
- return false;
- }
+class CreateBindings;
- bool operator != (const LookupItem &result) const
- { return ! operator == (result); }
-
-private:
- FullySpecifiedType _type;
- Symbol *_lastVisibleSymbol;
-};
-
-class CPLUSPLUS_EXPORT LookupContext
+class CPLUSPLUS_EXPORT ClassOrNamespace
{
public:
- LookupContext(Control *control = 0);
-
- LookupContext(Symbol *symbol,
- Document::Ptr expressionDocument,
- Document::Ptr thisDocument,
- const Snapshot &snapshot);
+ ClassOrNamespace(CreateBindings *factory, ClassOrNamespace *parent);
- bool isValid() const;
+ const TemplateNameId *templateId() const;
+ ClassOrNamespace *parent() const;
+ QList<ClassOrNamespace *> usings() const;
+ QList<Enum *> enums() const;
+ QList<Symbol *> symbols() const;
- Control *control() const;
- Symbol *symbol() const;
- Document::Ptr expressionDocument() const;
- Document::Ptr thisDocument() const;
- Document::Ptr document(const QString &fileName) const;
- Snapshot snapshot() const;
+ ClassOrNamespace *globalNamespace() const;
- static Symbol *canonicalSymbol(const QList<Symbol *> &candidates,
- NamespaceBinding *globalNamespaceBinding);
+ QList<Symbol *> lookup(const Name *name);
+ QList<Symbol *> find(const Name *name);
- static Symbol *canonicalSymbol(Symbol *symbol,
- NamespaceBinding *globalNamespaceBinding);
+ ClassOrNamespace *lookupType(const Name *name);
+ ClassOrNamespace *findType(const Name *name);
- static Symbol *canonicalSymbol(const QList<LookupItem> &candidates,
- NamespaceBinding *globalNamespaceBinding);
+private:
+ /// \internal
+ void flush();
- QList<Symbol *> resolve(const Name *name) const
- { return resolve(name, visibleScopes()); }
+ /// \internal
+ ClassOrNamespace *findOrCreateType(const Name *name);
- QList<Symbol *> resolveNamespace(const Name *name) const
- { return resolveNamespace(name, visibleScopes()); }
+ void addTodo(Symbol *symbol);
+ void addSymbol(Symbol *symbol);
+ void addEnum(Enum *e);
+ void addUsing(ClassOrNamespace *u);
+ void addNestedType(const Name *alias, ClassOrNamespace *e);
- QList<Symbol *> resolveClass(const Name *name) const
- { return resolveClass(name, visibleScopes()); }
+ QList<Symbol *> lookup_helper(const Name *name, bool searchInEnclosingScope);
- QList<Symbol *> resolveClassOrNamespace(const Name *name) const
- { return resolveClassOrNamespace(name, visibleScopes()); }
+ void lookup_helper(const Name *name, ClassOrNamespace *binding,
+ QList<Symbol *> *result,
+ QSet<ClassOrNamespace *> *processed,
+ const TemplateNameId *templateId);
- QList<Symbol *> resolveObjCClass(const Name *name) const
- { return resolveObjCClass(name, visibleScopes()); }
+ ClassOrNamespace *lookupType_helper(const Name *name, QSet<ClassOrNamespace *> *processed,
+ bool searchInEnclosingScope);
- QList<Symbol *> resolveObjCProtocol(const Name *name) const
- { return resolveObjCProtocol(name, visibleScopes()); }
+ ClassOrNamespace *nestedType(const Name *name) const;
- enum ResolveMode {
- ResolveSymbol = 0x01,
- ResolveClass = 0x02,
- ResolveNamespace = 0x04,
- ResolveClassOrNamespace = ResolveClass | ResolveNamespace,
- ResolveObjCClass = 0x08,
- ResolveObjCProtocol = 0x10,
- ResolveAll = ResolveSymbol | ResolveClassOrNamespace | ResolveObjCClass | ResolveObjCProtocol
+private:
+ struct CompareName: std::binary_function<const Name *, const Name *, bool> {
+ bool operator()(const Name *name, const Name *other) const;
};
- QList<Symbol *> resolve(const Name *name, const QList<Scope *> &visibleScopes,
- ResolveMode mode = ResolveAll) const;
-
- QList<Symbol *> resolveNamespace(const Name *name, const QList<Scope *> &visibleScopes) const
- { return resolve(name, visibleScopes, ResolveNamespace); }
-
- QList<Symbol *> resolveClass(const Name *name, const QList<Scope *> &visibleScopes) const
- { return resolve(name, visibleScopes, ResolveClass); }
-
- QList<Symbol *> resolveClassOrNamespace(const Name *name, const QList<Scope *> &visibleScopes) const
- { return resolve(name, visibleScopes, ResolveClassOrNamespace); }
-
- QList<Symbol *> resolveObjCClass(const Name *name, const QList<Scope *> &visibleScopes) const
- { return resolve(name, visibleScopes, ResolveObjCClass); }
-
- QList<Symbol *> resolveObjCProtocol(const Name *name, const QList<Scope *> &visibleScopes) const
- { return resolve(name, visibleScopes, ResolveObjCProtocol); }
-
- QList<Scope *> visibleScopes() const
- { return _visibleScopes; }
-
- QList<Scope *> visibleScopes(Symbol *symbol) const;
- QList<Scope *> visibleScopes(const LookupItem &result) const;
-
- QList<Scope *> expand(const QList<Scope *> &scopes) const;
-
- void expand(const QList<Scope *> &scopes, QList<Scope *> *expandedScopes) const;
-
- void expand(Scope *scope, const QList<Scope *> &visibleScopes,
- QList<Scope *> *expandedScopes) const;
-
- void expandNamespace(Namespace *namespaceSymbol,
- const QList<Scope *> &visibleScopes,
- QList<Scope *> *expandedScopes) const;
-
- void expandClass(Class *classSymbol,
- const QList<Scope *> &visibleScopes,
- QList<Scope *> *expandedScopes) const;
+private:
+ typedef std::map<const Name *, ClassOrNamespace *, CompareName> Table;
+ CreateBindings *_factory;
+ ClassOrNamespace *_parent;
+ QList<Symbol *> _symbols;
+ QList<ClassOrNamespace *> _usings;
+ Table _classOrNamespaces;
+ QList<Enum *> _enums;
+ QList<Symbol *> _todo;
+
+ // it's an instantiation.
+ const TemplateNameId *_templateId;
+
+ // templates
+ QList<ClassOrNamespace *> _instantiations;
+
+ friend class CreateBindings;
+};
- void expandBlock(Block *blockSymbol,
- const QList<Scope *> &visibleScopes,
- QList<Scope *> *expandedScopes) const;
+class CPLUSPLUS_EXPORT CreateBindings: protected SymbolVisitor
+{
+ Q_DISABLE_COPY(CreateBindings)
- void expandFunction(Function *functionSymbol,
- const QList<Scope *> &visibleScopes,
- QList<Scope *> *expandedScopes) const;
+public:
+ CreateBindings(Document::Ptr thisDocument, const Snapshot &snapshot, QSharedPointer<Control> control);
+ virtual ~CreateBindings();
+
+ /// Returns the binding for the global namespace.
+ ClassOrNamespace *globalNamespace() const;
+
+ /// Finds the binding associated to the given symbol.
+ ClassOrNamespace *lookupType(Symbol *symbol);
+
+ /// Returns the Control that must be used to create temporary symbols.
+ /// \internal
+ QSharedPointer<Control> control() const;
+
+ /// Searches in \a scope for symbols with the given \a name.
+ /// Store the result in \a results.
+ /// \internal
+ void lookupInScope(const Name *name, Scope *scope, QList<Symbol *> *result,
+ const TemplateNameId *templateId);
+
+ /// Create bindings for the symbols reachable from \a rootSymbol.
+ /// \internal
+ void process(Symbol *rootSymbol, ClassOrNamespace *classOrNamespace);
+
+ /// Create an empty ClassOrNamespace binding with the given \a parent.
+ /// \internal
+ ClassOrNamespace *allocClassOrNamespace(ClassOrNamespace *parent);
+
+protected:
+ using SymbolVisitor::visit;
+
+ /// Change the current ClassOrNamespace binding.
+ ClassOrNamespace *switchCurrentClassOrNamespace(ClassOrNamespace *classOrNamespace);
+
+ /// Enters the ClassOrNamespace binding associated with the given \a symbol.
+ ClassOrNamespace *enterClassOrNamespaceBinding(Symbol *symbol);
+
+ /// Enters a ClassOrNamespace binding for the given \a symbol in the global
+ /// namespace binding.
+ ClassOrNamespace *enterGlobalClassOrNamespace(Symbol *symbol);
+
+ /// Creates bindings for the given \a document.
+ void process(Document::Ptr document);
+
+ /// Creates bindings for the symbols reachable from the \a root symbol.
+ void process(Symbol *root);
+
+ virtual bool visit(Namespace *ns);
+ virtual bool visit(Class *klass);
+ virtual bool visit(ForwardClassDeclaration *klass);
+ virtual bool visit(Enum *e);
+ virtual bool visit(Declaration *decl);
+ virtual bool visit(Function *);
+ virtual bool visit(BaseClass *b);
+ virtual bool visit(UsingNamespaceDirective *u);
+ virtual bool visit(UsingDeclaration *u);
+ virtual bool visit(NamespaceAlias *a);
+
+ virtual bool visit(ObjCClass *klass);
+ virtual bool visit(ObjCBaseClass *b);
+ virtual bool visit(ObjCForwardClassDeclaration *klass);
+ virtual bool visit(ObjCProtocol *proto);
+ virtual bool visit(ObjCBaseProtocol *b);
+ virtual bool visit(ObjCForwardProtocolDeclaration *proto);
+ virtual bool visit(ObjCMethod *);
- void expandObjCMethod(ObjCMethod *method,
- const QList<Scope *> &visibleScopes,
- QList<Scope *> *expandedScopes) const;
+private:
+ Snapshot _snapshot;
+ QSharedPointer<Control> _control;
+ QSet<Namespace *> _processed;
+ QList<ClassOrNamespace *> _entities;
+ ClassOrNamespace *_globalNamespace;
+ ClassOrNamespace *_currentClassOrNamespace;
+};
- void expandObjCClass(ObjCClass *klass,
- const QList<Scope *> &visibleScopes,
- QList<Scope *> *expandedScopes) const;
+class CPLUSPLUS_EXPORT LookupContext
+{
+public:
+ LookupContext();
- void expandObjCProtocol(ObjCProtocol *protocol,
- const QList<Scope *> &visibleScopes,
- QList<Scope *> *expandedScopes) const;
+ LookupContext(Document::Ptr thisDocument,
+ const Snapshot &snapshot);
- void expandEnumOrAnonymousSymbol(ScopedSymbol *scopedSymbol,
- QList<Scope *> *expandedScopes) const;
+ LookupContext(Document::Ptr expressionDocument,
+ Document::Ptr thisDocument,
+ const Snapshot &snapshot);
-private:
- static Symbol *canonicalSymbol(Symbol *symbol);
+ LookupContext(const LookupContext &other);
+ LookupContext &operator = (const LookupContext &other);
- QList<Symbol *> resolveQualifiedNameId(const QualifiedNameId *q,
- const QList<Scope *> &visibleScopes,
- ResolveMode mode) const;
+ Document::Ptr expressionDocument() const;
+ Document::Ptr thisDocument() const;
+ Document::Ptr document(const QString &fileName) const;
+ Snapshot snapshot() const;
- QList<Symbol *> resolveOperatorNameId(const OperatorNameId *opId,
- const QList<Scope *> &visibleScopes,
- ResolveMode mode) const;
+ ClassOrNamespace *globalNamespace() const;
- QList<Scope *> resolveNestedNameSpecifier(const QualifiedNameId *q,
- const QList<Scope *> &visibleScopes) const;
+ QList<Symbol *> lookup(const Name *name, Scope *scope) const;
+ ClassOrNamespace *lookupType(const Name *name, Scope *scope) const;
+ ClassOrNamespace *lookupType(Symbol *symbol) const;
- const Identifier *identifier(const Name *name) const;
+ /// \internal
+ QSharedPointer<CreateBindings> bindings() const;
- QList<Scope *> buildVisibleScopes();
+ /// \internal
+ void setBindings(QSharedPointer<CreateBindings> bindings);
- void buildVisibleScopes_helper(Document::Ptr doc, QList<Scope *> *scopes,
- QSet<QString> *processed);
+ QSharedPointer<Control> control() const; // ### deprecate
- static bool maybeValidSymbol(Symbol *symbol,
- ResolveMode mode,
- const QList<Symbol *> &candidates);
+ static QList<const Name *> fullyQualifiedName(Symbol *symbol);
private:
- Control *_control;
-
- // The current symbol.
- Symbol *_symbol;
-
// The current expression.
Document::Ptr _expressionDocument;
// All documents.
Snapshot _snapshot;
- // Visible scopes.
- QList<Scope *> _visibleScopes;
-};
+ // Bindings
+ mutable QSharedPointer<CreateBindings> _bindings;
-uint qHash(const CPlusPlus::LookupItem &result);
+ QSharedPointer<Control> _control;
+};
} // end of namespace CPlusPlus
-#if defined(Q_CC_MSVC) && _MSC_VER <= 1300
-//this ensures that code outside QmlJS can use the hash function
-//it also a workaround for some compilers
-inline uint qHash(const CPlusPlus::LookupItem &item) { return CPlusPlus::qHash(item); }
-#endif
-
#endif // CPLUSPLUS_LOOKUPCONTEXT_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "LookupItem.h"
+#include <FullySpecifiedType.h>
+#include <Symbol.h>
+#include <Control.h>
+
+#include <QtDebug>
+
+using namespace CPlusPlus;
+
+uint CPlusPlus::qHash(const CPlusPlus::LookupItem &key)
+{
+ const uint h1 = QT_PREPEND_NAMESPACE(qHash)(key.type().type());
+ const uint h2 = QT_PREPEND_NAMESPACE(qHash)(key.scope());
+ return ((h1 << 16) | (h1 >> 16)) ^ h2;
+}
+
+LookupItem::LookupItem()
+ : _scope(0), _declaration(0)
+{ }
+
+FullySpecifiedType LookupItem::type() const
+{ return _type; }
+
+void LookupItem::setType(const FullySpecifiedType &type)
+{ _type = type; }
+
+Symbol *LookupItem::declaration() const
+{ return _declaration; }
+
+void LookupItem::setDeclaration(Symbol *declaration)
+{ _declaration = declaration; }
+
+Scope *LookupItem::scope() const
+{
+ if (! _scope && _declaration)
+ return _declaration->scope();
+
+ return _scope;
+}
+
+void LookupItem::setScope(Scope *scope)
+{ _scope = scope; }
+
+bool LookupItem::operator == (const LookupItem &other) const
+{
+ if (_type == other._type && _declaration == other._declaration && _scope == other._scope)
+ return true;
+
+ return false;
+}
+
+bool LookupItem::operator != (const LookupItem &result) const
+{ return ! operator == (result); }
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef CPLUSPLUS_LOOKUPITEM_H
+#define CPLUSPLUS_LOOKUPITEM_H
+
+#include <FullySpecifiedType.h>
+#include <QtCore/QHash>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT LookupItem
+{
+public:
+ /// Constructs an null LookupItem.
+ LookupItem();
+
+ /// Returns this item's type.
+ FullySpecifiedType type() const;
+
+ /// Sets this item's type.
+ void setType(const FullySpecifiedType &type);
+
+ /// Returns the last visible symbol.
+ Symbol *declaration() const;
+
+ /// Sets the last visible symbol.
+ void setDeclaration(Symbol *declaration);
+
+ /// Returns this item's scope.
+ Scope *scope() const;
+
+ /// Sets this item's scope.
+ void setScope(Scope *scope);
+
+ bool operator == (const LookupItem &other) const;
+ bool operator != (const LookupItem &other) const;
+
+private:
+ FullySpecifiedType _type;
+ Scope *_scope;
+ Symbol *_declaration;
+};
+
+uint qHash(const CPlusPlus::LookupItem &result);
+
+} // end of namespace CPlusPlus
+
+#if defined(Q_CC_MSVC) && _MSC_VER <= 1300
+//this ensures that code outside QmlJS can use the hash function
+//it also a workaround for some compilers
+inline uint qHash(const CPlusPlus::LookupItem &item) { return CPlusPlus::qHash(item); }
+#endif
+
+#endif // CPLUSPLUS_LOOKUPITEM_H
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef PP_MACRO_H
-#define PP_MACRO_H
+#ifndef CPLUSPLUS_PP_MACRO_H
+#define CPLUSPLUS_PP_MACRO_H
#include <CPlusPlusForwardDeclarations.h>
} // namespace CPlusPlus
-#endif // PP_MACRO_H
+#endif // CPLUSPLUS_PP_MACRO_H
**************************************************************************/
#include "MatchingText.h"
#include "BackwardsScanner.h"
+#include "TokenCache.h"
#include <Token.h>
return false;
}
-MatchingText::MatchingText()
+MatchingText::MatchingText(TokenCache *tokenCache)
+ : _tokenCache(tokenCache)
{ }
bool MatchingText::shouldInsertMatchingText(const QTextCursor &tc)
if (text.isEmpty() || !shouldInsertMatchingText(la))
return QString();
- BackwardsScanner tk(tc, textToProcess.left(*skippedChars), MAX_NUM_LINES);
+ BackwardsScanner tk(_tokenCache, tc, MAX_NUM_LINES, textToProcess.left(*skippedChars));
const int startToken = tk.startToken();
int index = startToken;
QString MatchingText::insertParagraphSeparator(const QTextCursor &tc) const
{
- BackwardsScanner tk(tc, QString(), MAX_NUM_LINES);
+ BackwardsScanner tk(_tokenCache, tc, MAX_NUM_LINES);
int index = tk.startToken();
if (tk[index - 1].isNot(T_LBRACE))
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
-#ifndef MATCHINGTEXT_H
-#define MATCHINGTEXT_H
+#ifndef CPLUSPLUS_MATCHINGTEXT_H
+#define CPLUSPLUS_MATCHINGTEXT_H
#include <CPlusPlusForwardDeclarations.h>
#include <QtGui/QTextCursor>
namespace CPlusPlus {
class BackwardsScanner;
+class TokenCache;
class CPLUSPLUS_EXPORT MatchingText
{
public:
- MatchingText();
+ MatchingText(TokenCache *tokenCache);
static bool shouldInsertMatchingText(const QTextCursor &tc);
static bool shouldInsertMatchingText(QChar lookAhead);
private:
bool shouldInsertNewline(const QTextCursor &tc) const;
+
+ TokenCache *_tokenCache;
};
} // end of namespace CPlusPlus
**
**************************************************************************/
-#ifndef OVERVIEW_H
-#define OVERVIEW_H
+#ifndef CPLUSPLUS_OVERVIEW_H
+#define CPLUSPLUS_OVERVIEW_H
#include <CPlusPlusForwardDeclarations.h>
#include <QString>
} // end of namespace CPlusPlus
-#endif // OVERVIEW_H
+#endif // CPLUSPLUS_OVERVIEW_H
#include "ResolveExpression.h"
#include "LookupContext.h"
#include "Overview.h"
-#include "GenTemplateInstance.h"
+#include "DeprecatedGenTemplateInstance.h"
#include <Control.h>
#include <AST.h>
#include <NameVisitor.h>
#include <QtCore/QList>
-#include <QtCore/QVarLengthArray>
#include <QtCore/QtDebug>
using namespace CPlusPlus;
namespace {
+const bool debug = ! qgetenv("CPLUSPLUS_DEBUG").isEmpty();
+
template <typename _Tp>
static QList<_Tp> removeDuplicates(const QList<_Tp> &results)
{
/////////////////////////////////////////////////////////////////////
ResolveExpression::ResolveExpression(const LookupContext &context)
: ASTVisitor(context.expressionDocument()->translationUnit()),
+ _scope(0),
_context(context),
sem(context.expressionDocument()->translationUnit())
{ }
ResolveExpression::~ResolveExpression()
{ }
-QList<LookupItem> ResolveExpression::operator()(ExpressionAST *ast)
+QList<LookupItem> ResolveExpression::operator()(ExpressionAST *ast, Scope *scope)
+{ return resolve(ast, scope); }
+
+QList<LookupItem> ResolveExpression::resolve(ExpressionAST *ast, Scope *scope)
+{
+ Q_ASSERT(scope != 0);
+
+ Scope *previousVisibleSymbol = _scope;
+ _scope = scope;
+ const QList<LookupItem> result = resolve(ast);
+ _scope = previousVisibleSymbol;
+ return result;
+}
+
+QList<LookupItem> ResolveExpression::resolve(ExpressionAST *ast)
{
const QList<LookupItem> previousResults = switchResults(QList<LookupItem>());
accept(ast);
return removeDuplicates(switchResults(previousResults));
}
-QList<LookupItem>
-ResolveExpression::switchResults(const QList<LookupItem> &results)
+QList<LookupItem> ResolveExpression::switchResults(const QList<LookupItem> &results)
{
const QList<LookupItem> previousResults = _results;
_results = results;
return previousResults;
}
-void ResolveExpression::addResults(const QList<LookupItem> &results)
+void ResolveExpression::addResults(const QList<Symbol *> &symbols)
{
- foreach (const LookupItem r, results)
- addResult(r);
+ foreach (Symbol *symbol, symbols) {
+ LookupItem item;
+ item.setType(symbol->type());
+ item.setScope(symbol->scope());
+ item.setDeclaration(symbol);
+ _results.append(item);
+ }
}
-void ResolveExpression::addResult(const FullySpecifiedType &ty, Symbol *symbol)
-{ return addResult(LookupItem(ty, symbol)); }
-
-void ResolveExpression::addResult(const LookupItem &r)
+void ResolveExpression::addResult(const FullySpecifiedType &ty, Scope *scope)
{
- LookupItem p = r;
+ LookupItem item;
+ item.setType(ty);
+ item.setScope(scope);
- if (! p.lastVisibleSymbol())
- p.setLastVisibleSymbol(_context.symbol());
-
- if (! _results.contains(p))
- _results.append(p);
+ _results.append(item);
}
-QList<Scope *> ResolveExpression::visibleScopes(const LookupItem &result) const
-{ return _context.visibleScopes(result); }
-
bool ResolveExpression::visit(BinaryExpressionAST *ast)
{
if (tokenKind(ast->binary_op_token) == T_COMMA && ast->right_expression && ast->right_expression->asQtMethod() != 0) {
QtMethodAST *qtMethod = ast->right_expression->asQtMethod();
if (DeclaratorAST *d = qtMethod->declarator) {
if (d->core_declarator) {
- if (DeclaratorIdAST *declaratorId = d->core_declarator->asDeclaratorId())
- if (NameAST *nameAST = declaratorId->name)
- _results = resolveMemberExpression(_results, T_ARROW, nameAST->name);
+ if (DeclaratorIdAST *declaratorId = d->core_declarator->asDeclaratorId()) {
+ if (NameAST *nameAST = declaratorId->name) {
+ if (ClassOrNamespace *binding = baseExpression(_results, T_ARROW)) {
+ _results.clear();
+ addResults(binding->lookup(nameAST->name));
+ }
+ }
+ }
}
}
bool ResolveExpression::visit(CastExpressionAST *ast)
{
- addResult(sem.check(ast->type_id, _context.expressionDocument()->globalSymbols()));
+ Scope *dummyScope = _context.expressionDocument()->globalSymbols();
+ FullySpecifiedType ty = sem.check(ast->type_id, dummyScope);
+ addResult(ty, _scope);
return false;
}
bool ResolveExpression::visit(CppCastExpressionAST *ast)
{
- addResult(sem.check(ast->type_id, _context.expressionDocument()->globalSymbols()));
+ Scope *dummyScope = _context.expressionDocument()->globalSymbols();
+ FullySpecifiedType ty = sem.check(ast->type_id, dummyScope);
+ addResult(ty, _scope);
return false;
}
bool ResolveExpression::visit(DeleteExpressionAST *)
{
FullySpecifiedType ty(control()->voidType());
- addResult(ty);
+ addResult(ty, _scope);
return false;
}
bool ResolveExpression::visit(NewExpressionAST *ast)
{
if (ast->new_type_id) {
- Scope *scope = _context.expressionDocument()->globalSymbols();
- FullySpecifiedType ty = sem.check(ast->new_type_id->type_specifier_list, scope);
- ty = sem.check(ast->new_type_id->ptr_operator_list, ty, scope);
+ Scope *dummyScope = _context.expressionDocument()->globalSymbols();
+ FullySpecifiedType ty = sem.check(ast->new_type_id->type_specifier_list, dummyScope);
+ ty = sem.check(ast->new_type_id->ptr_operator_list, ty, dummyScope);
FullySpecifiedType ptrTy(control()->pointerType(ty));
- addResult(ptrTy);
+ addResult(ptrTy, _scope);
}
// nothing to do.
return false;
const Name *q = control()->qualifiedNameId(std_type_info, 2, /*global=*/ true);
FullySpecifiedType ty(control()->namedType(q));
- addResult(ty);
+ addResult(ty, _scope);
return false;
}
{
accept(ast->base_expression);
- for (PostfixListAST *it = ast->postfix_expression_list; it; it = it->next) {
+ for (PostfixListAST *it = ast->postfix_expression_list; it; it = it->next)
accept(it->value);
- }
return false;
}
{
FullySpecifiedType ty(control()->integerType(IntegerType::Int));
ty.setUnsigned(true);
- addResult(ty);
+ addResult(ty, _scope);
return false;
}
if (literal->isUnsigned())
ty.setUnsigned(true);
- addResult(ty);
+ addResult(ty, _scope);
return false;
}
bool ResolveExpression::visit(BoolLiteralAST *)
{
FullySpecifiedType ty(control()->integerType(IntegerType::Bool));
- addResult(ty);
+ addResult(ty, _scope);
return false;
}
void ResolveExpression::thisObject()
{
- if (! _context.symbol())
- return;
-
- Scope *scope = _context.symbol()->scope();
+ Scope *scope = _scope;
for (; scope; scope = scope->enclosingScope()) {
if (scope->isFunctionScope()) {
Function *fun = scope->owner()->asFunction();
Class *klass = cscope->owner()->asClass();
FullySpecifiedType classTy(control()->namedType(klass->name()));
FullySpecifiedType ptrTy(control()->pointerType(classTy));
- addResult(ptrTy, fun);
+ addResult(ptrTy, fun->scope());
break;
} else if (const QualifiedNameId *q = fun->name()->asQualifiedNameId()) {
const Name *nestedNameSpecifier = 0;
nestedNameSpecifier = control()->qualifiedNameId(q->names(), q->nameCount() - 1);
FullySpecifiedType classTy(control()->namedType(nestedNameSpecifier));
FullySpecifiedType ptrTy(control()->pointerType(classTy));
- addResult(ptrTy, fun);
+ addResult(ptrTy, fun->scope());
break;
}
}
FullySpecifiedType charTy = control()->integerType(IntegerType::Char);
charTy.setConst(true);
FullySpecifiedType ty(control()->pointerType(charTy));
- addResult(ty);
+ addResult(ty, _scope);
return false;
}
bool ResolveExpression::visit(QualifiedNameAST *ast)
{
- ResolveClass resolveClass;
- const Name *name = ast->name;
-
- QList<Symbol *> symbols = _context.resolve(name);
- foreach (Symbol *symbol, symbols) {
- if (symbol->isTypedef()) {
- if (NamedType *namedTy = symbol->type()->asNamedType()) {
- const LookupItem r(namedTy, symbol);
- const QList<Symbol *> resolvedClasses =
- resolveClass(namedTy->name(), r, _context);
- if (resolvedClasses.count()) {
- foreach (Symbol *s, resolvedClasses) {
- addResult(s->type(), s);
- }
- continue;
- }
- }
- }
- addResult(symbol->type(), symbol);
+ if (const Name *name = ast->name) {
+ const QList<Symbol *> candidates = _context.lookup(name, _scope);
+ addResults(candidates);
}
- return false;
-}
-bool ResolveExpression::visit(OperatorFunctionIdAST *)
-{
return false;
}
-bool ResolveExpression::visit(ConversionFunctionIdAST *)
+bool ResolveExpression::visit(SimpleNameAST *ast)
{
+ const QList<Symbol *> candidates = _context.lookup(ast->name, _scope);
+ addResults(candidates);
return false;
}
-bool ResolveExpression::visit(SimpleNameAST *ast)
+bool ResolveExpression::visit(TemplateIdAST *ast)
{
- QList<Symbol *> symbols = _context.resolve(ast->name);
- foreach (Symbol *symbol, symbols)
- addResult(symbol->type(), symbol);
-
+ const QList<Symbol *> candidates = _context.lookup(ast->name, _scope);
+ addResults(candidates);
return false;
}
bool ResolveExpression::visit(DestructorNameAST *)
{
FullySpecifiedType ty(control()->voidType());
- addResult(ty);
+ addResult(ty, _scope);
return false;
}
-bool ResolveExpression::visit(TemplateIdAST *ast)
+bool ResolveExpression::visit(OperatorFunctionIdAST *)
{
- QList<Symbol *> symbols = _context.resolve(ast->name);
- foreach (Symbol *symbol, symbols)
- addResult(symbol->type(), symbol);
+ return false;
+}
+bool ResolveExpression::visit(ConversionFunctionIdAST *)
+{
return false;
}
bool ResolveExpression::visit(CallAST *ast)
{
- ResolveClass resolveClass;
-
const QList<LookupItem> baseResults = _results;
_results.clear();
//QList< QList<Result> > arguments;
for (ExpressionListAST *exprIt = ast->expression_list; exprIt; exprIt = exprIt->next) {
- //arguments.append(operator()(exprIt->expression));
+ //arguments.append(resolve(exprIt->expression));
++actualArgumentCount;
}
foreach (const LookupItem &result, baseResults) {
FullySpecifiedType ty = result.type().simplified();
- Symbol *lastVisibleSymbol = result.lastVisibleSymbol();
+ Scope *scope = result.scope();
if (NamedType *namedTy = ty->asNamedType()) {
- const QList<Symbol *> classObjectCandidates = resolveClass(namedTy->name(), result, _context);
-
- foreach (Symbol *classObject, classObjectCandidates) {
- const QList<LookupItem> overloads = resolveMember(functionCallOp, classObject->asClass(), namedTy->name());
-
- foreach (const LookupItem &o, overloads) {
- FullySpecifiedType overloadTy = o.type().simplified();
-
- if (Function *funTy = overloadTy->asFunctionType()) {
- if (maybeValidPrototype(funTy, actualArgumentCount))
- addResult(funTy->returnType().simplified(), lastVisibleSymbol);
+ if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) {
+ foreach (Symbol *overload, b->find(functionCallOp)) {
+ if (Function *funTy = overload->type()->asFunctionType()) {
+ if (maybeValidPrototype(funTy, actualArgumentCount)) {
+ if (Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType())
+ addResult(proto->returnType().simplified(), scope);
+ }
}
}
}
} else if (Function *funTy = ty->asFunctionType()) {
if (maybeValidPrototype(funTy, actualArgumentCount))
- addResult(funTy->returnType().simplified(), lastVisibleSymbol);
+ addResult(funTy->returnType().simplified(), scope);
} else if (Class *classTy = ty->asClassType()) {
// Constructor call
FullySpecifiedType ctorTy = control()->namedType(classTy->name());
- addResult(ctorTy, lastVisibleSymbol);
+ addResult(ctorTy, scope);
}
}
const QList<LookupItem> baseResults = _results;
_results.clear();
- const QList<LookupItem> indexResults = operator()(ast->expression);
- ResolveClass resolveClass;
+ const QList<LookupItem> indexResults = resolve(ast->expression);
const Name *arrayAccessOp = control()->operatorNameId(OperatorNameId::ArrayAccessOp);
foreach (const LookupItem &result, baseResults) {
FullySpecifiedType ty = result.type().simplified();
- Symbol *contextSymbol = result.lastVisibleSymbol();
+ Scope *scope = result.scope();
if (PointerType *ptrTy = ty->asPointerType()) {
- addResult(ptrTy->elementType().simplified(), contextSymbol);
+ addResult(ptrTy->elementType().simplified(), scope);
} else if (ArrayType *arrTy = ty->asArrayType()) {
- addResult(arrTy->elementType().simplified(), contextSymbol);
+ addResult(arrTy->elementType().simplified(), scope);
} else if (NamedType *namedTy = ty->asNamedType()) {
- const QList<Symbol *> classObjectCandidates =
- resolveClass(namedTy->name(), result, _context);
-
- foreach (Symbol *classObject, classObjectCandidates) {
- Q_ASSERT(classObject->isClass());
-
- const QList<LookupItem> overloads =
- resolveMember(arrayAccessOp, classObject->asClass(), namedTy->name());
-
- foreach (LookupItem r, overloads) {
- FullySpecifiedType ty = r.type().simplified();
- if (Function *funTy = ty->asFunctionType()) {
- ty = funTy->returnType().simplified();
- addResult(ty, funTy);
+ if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) {
+ foreach (Symbol *overload, b->find(arrayAccessOp)) {
+ if (Function *funTy = overload->type()->asFunctionType()) {
+ if (Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType())
+ // ### TODO: check the actual arguments
+ addResult(proto->returnType().simplified(), scope);
}
}
+
}
}
}
{
// The candidate types for the base expression are stored in
// _results.
- QList<LookupItem> baseResults = _results;
+ const QList<LookupItem> baseResults = _results;
+ _results.clear();
// Evaluate the expression-id that follows the access operator.
const Name *memberName = 0;
// Remember the access operator.
const int accessOp = tokenKind(ast->access_token);
- _results = resolveMemberExpression(baseResults, accessOp, memberName);
+ if (ClassOrNamespace *binding = baseExpression(baseResults, accessOp))
+ addResults(binding->lookup(memberName));
return false;
}
-QList<LookupItem>
-ResolveExpression::resolveBaseExpression(const QList<LookupItem> &baseResults, int accessOp,
- bool *replacedDotOperator) const
+ClassOrNamespace *ResolveExpression::findClass(const FullySpecifiedType &originalTy, Scope *scope) const
{
- QList<LookupItem> results;
-
- if (baseResults.isEmpty())
- return results;
-
- LookupItem result = baseResults.first();
- FullySpecifiedType ty = result.type().simplified();
- Symbol *lastVisibleSymbol = result.lastVisibleSymbol();
-
- if (Function *funTy = ty->asFunctionType()) {
- if (funTy->isAmbiguous())
- ty = funTy->returnType().simplified();
- }
-
- if (accessOp == T_ARROW) {
- if (lastVisibleSymbol && ty->isClassType() && ! lastVisibleSymbol->isClass()) {
- // ### remove ! lastVisibleSymbol->isClass() from the condition.
- results.append(LookupItem(ty, lastVisibleSymbol));
-
- } else if (NamedType *namedTy = ty->asNamedType()) {
- // ### This code is pretty slow.
- const QList<Symbol *> candidates = _context.resolve(namedTy->name());
-
- foreach (Symbol *candidate, candidates) {
- if (candidate->isTypedef()) {
- FullySpecifiedType declTy = candidate->type().simplified();
- const LookupItem r(declTy, candidate);
-
- // update the result
- result = r;
-
- // refresh the cached ty and lastVisibileSymbol.
- ty = result.type().simplified();
- lastVisibleSymbol = result.lastVisibleSymbol();
- break;
- }
- }
- }
-
- if (NamedType *namedTy = ty->asNamedType()) {
- ResolveClass resolveClass;
- const Name *arrowAccessOp = control()->operatorNameId(OperatorNameId::ArrowOp);
- const QList<Symbol *> candidates = resolveClass(namedTy->name(), result, _context);
+ FullySpecifiedType ty = originalTy.simplified();
+ ClassOrNamespace *binding = 0;
- foreach (Symbol *classObject, candidates) {
- const QList<LookupItem> overloads = resolveMember(arrowAccessOp, classObject->asClass(),
- namedTy->name());
+ if (Class *klass = ty->asClassType())
+ binding = _context.lookupType(klass);
- foreach (const LookupItem &r, overloads) {
- FullySpecifiedType typeOfOverloadFunction = r.type().simplified();
- Symbol *lastVisibleSymbol = r.lastVisibleSymbol();
- Function *funTy = typeOfOverloadFunction->asFunctionType();
- if (! funTy)
- continue;
+ else if (NamedType *namedTy = ty->asNamedType())
+ binding = _context.lookupType(namedTy->name(), scope);
- typeOfOverloadFunction = funTy->returnType().simplified();
+ else if (Function *funTy = ty->asFunctionType())
+ return findClass(funTy->returnType(), scope);
- if (PointerType *ptrTy = typeOfOverloadFunction->asPointerType()) {
- FullySpecifiedType elementTy = ptrTy->elementType().simplified();
-
- if (elementTy->isNamedType())
- results.append(LookupItem(elementTy, lastVisibleSymbol));
- }
- }
- }
- } else if (PointerType *ptrTy = ty->asPointerType()) {
- FullySpecifiedType elementTy = ptrTy->elementType().simplified();
-
- if (elementTy->isNamedType() || elementTy->isClassType())
- results.append(LookupItem(elementTy, lastVisibleSymbol));
- }
- } else if (accessOp == T_DOT) {
- if (replacedDotOperator) {
- if (PointerType *ptrTy = ty->asPointerType()) {
- *replacedDotOperator = true;
- ty = ptrTy->elementType().simplified();
- } else if (ArrayType *arrTy = ty->asArrayType()) {
- *replacedDotOperator = true;
- ty = arrTy->elementType().simplified();
- }
- }
-
- if (NamedType *namedTy = ty->asNamedType()) {
- const QList<Scope *> visibleScopes = _context.visibleScopes(result);
- const QList<Symbol *> candidates = _context.resolve(namedTy->name(), visibleScopes);
- foreach (Symbol *candidate, candidates) {
- if (candidate->isTypedef() && candidate->type()->isNamedType()) {
- ty = candidate->type();
- lastVisibleSymbol = candidate;
- break;
- } else if (TypenameArgument *arg = candidate->asTypenameArgument()) {
- ty = arg->type();
- lastVisibleSymbol = candidate;
- break;
- }
- }
-
- results.append(LookupItem(ty, lastVisibleSymbol));
-
- } else if (Function *fun = ty->asFunctionType()) {
- Scope *funScope = fun->scope();
-
- if (funScope && (funScope->isBlockScope() || funScope->isNamespaceScope())) {
- FullySpecifiedType retTy = fun->returnType().simplified();
- results.append(LookupItem(retTy, lastVisibleSymbol));
- }
- }
- }
-
- return removeDuplicates(results);
-}
-
-QList<LookupItem>
-ResolveExpression::resolveMemberExpression(const QList<LookupItem> &baseResults,
- unsigned accessOp,
- const Name *memberName,
- bool *replacedDotOperator) const
-{
- ResolveClass resolveClass;
- QList<LookupItem> results;
-
- const QList<LookupItem> classObjectResults = resolveBaseExpression(baseResults, accessOp, replacedDotOperator);
- foreach (const LookupItem &r, classObjectResults) {
- FullySpecifiedType ty = r.type();
-
- if (Class *klass = ty->asClassType())
- results += resolveMember(memberName, klass);
-
- else if (NamedType *namedTy = ty->asNamedType()) {
- const Name *className = namedTy->name();
- const QList<Symbol *> classes = resolveClass(className, r, _context);
-
- foreach (Symbol *c, classes) {
- if (Class *klass = c->asClass())
- results += resolveMember(memberName, klass, className);
- }
- }
- }
-
- return removeDuplicates(results);
+ return binding;
}
-QList<LookupItem>
-ResolveExpression::resolveMember(const Name *memberName, Class *klass,
- const Name *className) const
+ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &baseResults,
+ int accessOp,
+ bool *replacedDotOperator) const
{
- QList<LookupItem> results;
-
- if (! className)
- className = klass->name();
-
- if (! className)
- return results;
+ foreach (const LookupItem &r, baseResults) {
+ FullySpecifiedType ty = r.type().simplified();
+ Scope *scope = r.scope();
- QList<Scope *> scopes;
- _context.expand(klass->members(), _context.visibleScopes(), &scopes);
-
- const QList<Symbol *> candidates = _context.resolve(memberName, scopes);
-
- foreach (Symbol *candidate, candidates) {
- FullySpecifiedType ty = candidate->type();
- const Name *unqualifiedNameId = className;
-
- if (const QualifiedNameId *q = className->asQualifiedNameId())
- unqualifiedNameId = q->unqualifiedNameId();
-
- if (const TemplateNameId *templId = unqualifiedNameId->asTemplateNameId()) {
- GenTemplateInstance::Substitution subst;
-
- for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
- FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
-
- if (i < klass->templateParameterCount()) {
- const Name *templArgName = klass->templateParameterAt(i)->name();
- if (templArgName && templArgName->identifier()) {
- const Identifier *templArgId = templArgName->identifier();
- subst.append(qMakePair(templArgId, templArgTy));
+ if (accessOp == T_ARROW) {
+ if (PointerType *ptrTy = ty->asPointerType()) {
+ if (ClassOrNamespace *binding = findClass(ptrTy->elementType(), scope))
+ return binding;
+
+ } else if (ClassOrNamespace *binding = findClass(ty, scope)) {
+ // lookup for overloads of operator->
+ const OperatorNameId *arrowOp = control()->operatorNameId(OperatorNameId::ArrowOp);
+
+ foreach (Symbol *overload, binding->find(arrowOp)) {
+ if (overload->type()->isFunctionType()) {
+ FullySpecifiedType overloadTy = instantiate(binding->templateId(), overload);
+ Function *instantiatedFunction = overloadTy->asFunctionType();
+ Q_ASSERT(instantiatedFunction != 0);
+
+ FullySpecifiedType retTy = instantiatedFunction->returnType().simplified();
+
+ if (PointerType *ptrTy = retTy->asPointerType()) {
+ if (ClassOrNamespace *retBinding = findClass(ptrTy->elementType(), overload->scope()))
+ return retBinding;
+
+ else if (debug) {
+ Overview oo;
+ qDebug() << "no class for:" << oo(ptrTy->elementType());
+ }
+ }
}
}
}
+ } else if (accessOp == T_DOT) {
+ if (replacedDotOperator) {
+ if (PointerType *ptrTy = ty->asPointerType()) {
+ // replace . with ->
+ ty = ptrTy->elementType();
+ *replacedDotOperator = true;
+ }
+ }
- GenTemplateInstance inst(_context, subst);
- ty = inst(candidate);
+ if (ClassOrNamespace *binding = findClass(ty, scope))
+ return binding;
}
-
- results.append(LookupItem(ty, candidate));
}
- return removeDuplicates(results);
+ return 0;
}
-
-QList<LookupItem>
-ResolveExpression::resolveMember(const Name *memberName, ObjCClass *klass) const
+FullySpecifiedType ResolveExpression::instantiate(const Name *className, Symbol *candidate) const
{
- QList<LookupItem> results;
-
- if (!memberName || !klass)
- return results;
-
- QList<Scope *> scopes;
- _context.expand(klass->members(), _context.visibleScopes(), &scopes);
-
- QList<Symbol *> candidates = _context.resolve(memberName, scopes);
-
- foreach (Symbol *candidate, candidates) {
- FullySpecifiedType ty = candidate->type();
-
- results.append(LookupItem(ty, candidate));
- }
-
- return removeDuplicates(results);
+ return DeprecatedGenTemplateInstance::instantiate(className, candidate, _context.control());
}
bool ResolveExpression::visit(PostIncrDecrAST *)
bool ResolveExpression::visit(ObjCMessageExpressionAST *ast)
{
- QList<LookupItem> receiverResults = operator()(ast->receiver_expression);
+ const QList<LookupItem> receiverResults = resolve(ast->receiver_expression);
- if (!receiverResults.isEmpty()) {
- LookupItem result = receiverResults.first();
+ foreach (const LookupItem &result, receiverResults) {
FullySpecifiedType ty = result.type().simplified();
- const Name *klassName = 0;
+ ClassOrNamespace *binding = 0;
- if (const ObjCClass *classTy = ty->asObjCClassType()) {
+ if (ObjCClass *clazz = ty->asObjCClassType()) {
// static access, e.g.:
- // [NSObject description];
- klassName = classTy->name();
- } else if (const PointerType *ptrTy = ty->asPointerType()) {
- const FullySpecifiedType pointeeTy = ptrTy->elementType();
- if (pointeeTy && pointeeTy->isNamedType()) {
+ // [NSObject description];
+ binding = _context.lookupType(clazz);
+ } else if (PointerType *ptrTy = ty->asPointerType()) {
+ if (NamedType *namedTy = ptrTy->asNamedType()) {
// dynamic access, e.g.:
- // NSObject *obj = ...; [obj release];
- klassName = pointeeTy->asNamedType()->name();
+ // NSObject *obj = ...; [obj release];
+ binding = _context.lookupType(namedTy->name(), result.scope());
}
}
- if (klassName&&ast->selector && ast->selector->name) {
- ResolveObjCClass resolveObjCClass;
- QList<Symbol *> resolvedSymbols = resolveObjCClass(klassName, result, _context);
- foreach (Symbol *resolvedSymbol, resolvedSymbols)
- if (ObjCClass *klass = resolvedSymbol->asObjCClass())
- _results.append(resolveMember(ast->selector->name, klass));
+ if (binding) {
+ foreach (Symbol *s, binding->lookup(ast->selector->name))
+ if (ObjCMethod *m = s->asObjCMethod())
+ addResult(m->returnType(), result.scope());
}
}
return false;
}
-////////////////////////////////////////////////////////////////////////////////
-ResolveClass::ResolveClass()
-{ }
-
-QList<Symbol *> ResolveClass::operator()(const Name *name,
- const LookupItem &p,
- const LookupContext &context)
-{
- const QList<LookupItem> previousBlackList = _blackList;
- const QList<Symbol *> symbols = resolveClass(name, p, context);
- _blackList = previousBlackList;
- return symbols;
-}
-
-QList<Symbol *> ResolveClass::resolveClass(const Name *name,
- const LookupItem &p,
- const LookupContext &context)
-{
- QList<Symbol *> resolvedSymbols;
-
- if (_blackList.contains(p))
- return resolvedSymbols;
-
- _blackList.append(p);
-
- const QList<Symbol *> candidates =
- context.resolve(name, context.visibleScopes(p));
-
- foreach (Symbol *candidate, candidates) {
- if (Class *klass = candidate->asClass()) {
- if (resolvedSymbols.contains(klass))
- continue; // we already know about `klass'
- resolvedSymbols.append(klass);
- } else if (candidate->isTypedef()) {
- if (Declaration *decl = candidate->asDeclaration()) {
- if (Class *asClass = decl->type()->asClassType()) {
- // typedef struct { } Point;
- // Point pt;
- // pt.
- resolvedSymbols.append(asClass);
- } else {
- // typedef Point Boh;
- // Boh b;
- // b.
- FullySpecifiedType declType = decl->type().simplified();
- if (NamedType *namedTy = declType->asNamedType()) {
- const LookupItem r(declType, decl);
- resolvedSymbols += resolveClass(namedTy->name(), r, context);
- }
- }
- }
- } else if (Declaration *decl = candidate->asDeclaration()) {
- if (Function *funTy = decl->type()->asFunctionType()) {
- // QString foo("ciao");
- // foo.
- if (funTy->scope() && (funTy->scope()->isBlockScope() || funTy->scope()->isNamespaceScope())) {
- FullySpecifiedType retTy = funTy->returnType().simplified();
- if (NamedType *namedTy = retTy->asNamedType()) {
- const LookupItem r(retTy, decl);
- resolvedSymbols += resolveClass(namedTy->name(), r, context);
- }
- }
- }
- }
- }
-
- return resolvedSymbols;
-}
-
-ResolveObjCClass::ResolveObjCClass()
-{}
-
-QList<Symbol *> ResolveObjCClass::operator ()(const Name *name,
- const LookupItem &p,
- const LookupContext &context)
-{
- QList<Symbol *> resolvedSymbols;
-
- const QList<Symbol *> candidates =
- context.resolve(name, context.visibleScopes(p));
-
- foreach (Symbol *candidate, candidates) {
- if (ObjCClass *klass = candidate->asObjCClass()) {
- if (resolvedSymbols.contains(klass))
- continue; // we already know about `klass'
- resolvedSymbols.append(klass);
- } else if (candidate->isTypedef()) {
- if (Declaration *decl = candidate->asDeclaration()) {
- if (decl->type()->isObjCClassType()) {
- ObjCClass *klass = decl->type()->asObjCClassType();
- if (resolvedSymbols.contains(klass))
- continue;
- resolvedSymbols.append(klass);
- }
- }
- }
- }
-
- return resolvedSymbols;
-}
ResolveExpression(const LookupContext &context);
virtual ~ResolveExpression();
- QList<LookupItem> operator()(ExpressionAST *ast);
+ QList<LookupItem> operator()(ExpressionAST *ast, Scope *scope);
+ QList<LookupItem> resolve(ExpressionAST *ast, Scope *scope);
- QList<LookupItem> resolveMemberExpression(const QList<LookupItem> &baseResults,
- unsigned accessOp,
- const Name *memberName,
- bool *replacedDotOperator = 0) const;
+ ClassOrNamespace *baseExpression(const QList<LookupItem> &baseResults,
+ int accessOp,
+ bool *replacedDotOperator = 0) const;
- QList<LookupItem> resolveBaseExpression(const QList<LookupItem> &baseResults,
- int accessOp,
- bool *replacedDotOperator = 0) const;
-
- QList<LookupItem> resolveMember(const Name *memberName, Class *klass,
- const Name *className = 0) const;
+protected:
+ ClassOrNamespace *findClass(const FullySpecifiedType &ty, Scope *scope) const;
- QList<LookupItem> resolveMember(const Name *memberName, ObjCClass *klass) const;
+ QList<LookupItem> resolve(ExpressionAST *ast);
-protected:
QList<LookupItem> switchResults(const QList<LookupItem> &symbols);
+ FullySpecifiedType instantiate(const Name *className, Symbol *candidate) const;
void thisObject();
- void addResult(const FullySpecifiedType &ty, Symbol *symbol = 0);
- void addResult(const LookupItem &result);
- void addResults(const QList<LookupItem> &results);
+
+ void addResult(const FullySpecifiedType &ty, Scope *scope);
+ void addResults(const QList<Symbol *> &symbols);
bool maybeValidPrototype(Function *funTy, unsigned actualArgumentCount) const;
// Objective-C expressions
virtual bool visit(ObjCMessageExpressionAST *ast);
- QList<Scope *> visibleScopes(const LookupItem &result) const;
-
private:
+ Scope *_scope;
LookupContext _context;
Semantic sem;
QList<LookupItem> _results;
Symbol *_declSymbol;
};
-class CPLUSPLUS_EXPORT ResolveClass
-{
-public:
- ResolveClass();
-
- QList<Symbol *> operator()(const Name *name,
- const LookupItem &p,
- const LookupContext &context);
-
-private:
- QList<Symbol *> resolveClass(const Name *name,
- const LookupItem &p,
- const LookupContext &context);
-
-private:
- QList<LookupItem> _blackList;
-};
-
-class CPLUSPLUS_EXPORT ResolveObjCClass
-{
-public:
- ResolveObjCClass();
-
- QList<Symbol *> operator()(const Name *name,
- const LookupItem &p,
- const LookupContext &context);
-};
-
-
} // end of namespace CPlusPlus
#endif // CPLUSPLUS_RESOLVEEXPRESSION_H
using namespace CPlusPlus;
-SimpleToken::SimpleToken(const Token &token, const QStringRef &text)
+SimpleToken::SimpleToken(const Token &token)
: _kind(token.f.kind)
, _flags(0)
, _position(token.begin())
, _length(token.f.length)
- , _text(text)
{
f._whitespace = token.f.whitespace;
f._newline = token.f.newline;
break;
QStringRef spell = text.midRef(lex.tokenOffset(), lex.tokenLength());
- SimpleToken simpleTk(tk, spell);
+ SimpleToken simpleTk(tk);
lex.setScanAngleStringLiteralTokens(false);
if (tk.f.newline && tk.is(T_POUND))
inPreproc = true;
else if (inPreproc && tokens.size() == 1 && simpleTk.is(T_IDENTIFIER) &&
- simpleTk.text() == QLatin1String("include"))
+ spell == QLatin1String("include"))
lex.setScanAngleStringLiteralTokens(true);
else if (_objCEnabled
&& inPreproc && tokens.size() == 1 && simpleTk.is(T_IDENTIFIER) &&
- simpleTk.text() == QLatin1String("import"))
+ spell == QLatin1String("import"))
lex.setScanAngleStringLiteralTokens(true);
if (_objCEnabled && tk.is(T_IDENTIFIER))
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
-#ifndef SIMPLELEXER_H
-#define SIMPLELEXER_H
+#ifndef CPLUSPLUS_SIMPLELEXER_H
+#define CPLUSPLUS_SIMPLELEXER_H
#include <CPlusPlusForwardDeclarations.h>
class CPLUSPLUS_EXPORT SimpleToken
{
public:
- SimpleToken(const Token &token, const QStringRef &text);
+ SimpleToken(const Token &token);
SimpleToken()
: _kind(0)
inline int end() const
{ return _position + _length; }
- inline QStringRef text() const
- { return _text; }
-
inline bool followsNewline() const
{ return f._newline; }
inline void setPosition(int position)
{ _position = position; }
- // internal
- inline void setText(const QStringRef &text)
- { _text = text; }
-
public:
short _kind;
union {
short _flags;
struct {
- short _newline: 1;
- short _whitespace: 1;
- short _objcTypeQualifier: 1;
+ unsigned _newline: 1;
+ unsigned _whitespace: 1;
+ unsigned _objcTypeQualifier: 1;
} f;
};
int _position;
int _length;
- QStringRef _text;
friend class SimpleLexer;
};
} // end of namespace CPlusPlus
-#endif // SIMPLELEXER_H
+#endif // CPLUSPLUS_SIMPLELEXER_H
--- /dev/null
+#include "SimpleLexer.h"
+#include "TokenCache.h"
+
+using namespace CPlusPlus;
+
+TokenCache::TokenCache()
+ : m_doc(0)
+ , m_revision(-1)
+{}
+
+void TokenCache::setDocument(QTextDocument *doc)
+{
+ m_doc = doc;
+ m_revision = -1;
+}
+
+QList<SimpleToken> TokenCache::tokensForBlock(const QTextBlock &block) const
+{
+ Q_ASSERT(m_doc);
+ Q_ASSERT(m_doc == block.document());
+
+ const int documentRevision = m_doc->revision();
+
+ if (documentRevision != m_revision) {
+ m_tokensByBlock.clear();
+ m_revision = documentRevision;
+ }
+
+ const int blockNr = block.blockNumber();
+
+ if (m_tokensByBlock.contains(blockNr)) {
+ return m_tokensByBlock.value(blockNr);
+ } else {
+
+ SimpleLexer tokenize;
+ tokenize.setObjCEnabled(true);
+ tokenize.setQtMocRunEnabled(true);
+ tokenize.setSkipComments(false);
+
+ const int prevState = previousBlockState(block);
+ QList<SimpleToken> tokens = tokenize(block.text(), prevState);
+ m_tokensByBlock.insert(blockNr, tokens);
+
+ return tokens;
+ }
+}
+
+SimpleToken TokenCache::tokenUnderCursor(const QTextCursor &cursor) const
+{
+ const QTextBlock block = cursor.block();
+ const QList<SimpleToken> tokens = tokensForBlock(block);
+ const int column = cursor.position() - block.position();
+
+ for (int index = tokens.size() - 1; index >= 0; --index) {
+ const SimpleToken &tk = tokens.at(index);
+ if (tk.position() < column)
+ return tk;
+ }
+
+ return SimpleToken();
+}
+
+QString TokenCache::text(const QTextBlock &block, int tokenIndex) const
+{
+ SimpleToken tk = tokensForBlock(block).at(tokenIndex);
+ return block.text().mid(tk.position(), tk.length());
+}
+
+int TokenCache::previousBlockState(const QTextBlock &block)
+{
+ const QTextBlock prevBlock = block.previous();
+
+ if (prevBlock.isValid()) {
+ int state = prevBlock.userState();
+
+ if (state != -1)
+ return state;
+ }
+
+ return 0;
+}
--- /dev/null
+#ifndef TOKENCACHE_H
+#define TOKENCACHE_H
+
+#include <CPlusPlusForwardDeclarations.h>
+#include <cplusplus/SimpleLexer.h>
+
+#include <QtCore/QHash>
+#include <QtCore/QList>
+
+#include <QtGui/QTextBlock>
+#include <QtGui/QTextCursor>
+#include <QtGui/QTextDocument>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT TokenCache
+{
+public:
+ TokenCache();
+
+ void setDocument(QTextDocument *doc);
+
+ QList<CPlusPlus::SimpleToken> tokensForBlock(const QTextBlock &block) const;
+ CPlusPlus::SimpleToken tokenUnderCursor(const QTextCursor &cursor) const;
+
+ QString text(const QTextBlock &block, int tokenIndex) const;
+
+ static int previousBlockState(const QTextBlock &block);
+
+private:
+ QTextDocument *m_doc;
+
+ mutable int m_revision;
+ mutable QHash<int, QList<CPlusPlus::SimpleToken> > m_tokensByBlock;
+};
+
+} // namespace CPlusPlus
+
+#endif // TOKENCACHE_H
#include "pp.h"
#include <AST.h>
+#include <Symbol.h>
#include <QSet>
using namespace CPlusPlus;
TypeOfExpression::TypeOfExpression():
- m_ast(0)
+ m_ast(0),
+ m_scope(0)
{
}
-Snapshot TypeOfExpression::snapshot() const
+void TypeOfExpression::reset()
{
- return m_snapshot;
+ m_thisDocument.clear();
+ m_snapshot = Snapshot();
+ m_ast = 0;
+ m_scope = 0;
+ m_lookupContext = LookupContext();
+ m_bindings.clear();
+ m_environment.clear();
}
-void TypeOfExpression::setSnapshot(const Snapshot &documents)
+void TypeOfExpression::init(Document::Ptr thisDocument, const Snapshot &snapshot,
+ QSharedPointer<CreateBindings> bindings)
{
- m_snapshot = documents;
+ m_thisDocument = thisDocument;
+ m_snapshot = snapshot;
+ m_ast = 0;
+ m_scope = 0;
m_lookupContext = LookupContext();
+ m_bindings = bindings;
+ m_environment.clear();
}
QList<LookupItem> TypeOfExpression::operator()(const QString &expression,
- Document::Ptr document,
- Symbol *lastVisibleSymbol,
- PreprocessMode mode)
+ Scope *scope,
+ PreprocessMode mode)
{
QString code = expression;
+
if (mode == Preprocess)
- code = preprocessedExpression(expression, m_snapshot, document);
+ code = preprocessedExpression(expression);
+
Document::Ptr expressionDoc = documentForExpression(code);
expressionDoc->check();
m_ast = extractExpressionAST(expressionDoc);
- m_lookupContext = LookupContext(lastVisibleSymbol, expressionDoc,
- document, m_snapshot);
+ m_scope = scope;
- ResolveExpression resolveExpression(m_lookupContext);
- return resolveExpression(m_ast);
+ m_lookupContext = LookupContext(expressionDoc, m_thisDocument, m_snapshot);
+ m_lookupContext.setBindings(m_bindings);
+
+ ResolveExpression resolve(m_lookupContext);
+ return resolve(m_ast, scope);
}
-QString TypeOfExpression::preprocess(const QString &expression,
- Document::Ptr document) const
+QString TypeOfExpression::preprocess(const QString &expression) const
{
- return preprocessedExpression(expression, m_snapshot, document);
+ return preprocessedExpression(expression);
}
ExpressionAST *TypeOfExpression::ast() const
return m_ast;
}
-const LookupContext &TypeOfExpression::lookupContext() const
+Scope *TypeOfExpression::scope() const
+{
+ return m_scope;
+}
+
+const LookupContext &TypeOfExpression::context() const
{
return m_lookupContext;
}
return doc;
}
-void TypeOfExpression::processEnvironment(Snapshot documents,
- Document::Ptr doc, Environment *env,
+void TypeOfExpression::processEnvironment(Document::Ptr doc, Environment *env,
QSet<QString> *processed) const
{
- if (! doc)
- return;
- if (processed->contains(doc->fileName()))
- return;
- processed->insert(doc->fileName());
- foreach (const Document::Include &incl, doc->includes()) {
- processEnvironment(documents,
- documents.document(incl.fileName()),
- env, processed);
+ if (doc && ! processed->contains(doc->fileName())) {
+ processed->insert(doc->fileName());
+
+ foreach (const Document::Include &incl, doc->includes())
+ processEnvironment(m_snapshot.document(incl.fileName()), env, processed);
+
+ foreach (const Macro ¯o, doc->definedMacros())
+ env->bind(macro);
}
- foreach (const Macro ¯o, doc->definedMacros())
- env->bind(macro);
}
-QString TypeOfExpression::preprocessedExpression(const QString &expression,
- Snapshot documents,
- Document::Ptr thisDocument) const
+QString TypeOfExpression::preprocessedExpression(const QString &expression) const
{
if (expression.trimmed().isEmpty())
return expression;
- Environment env;
- QSet<QString> processed;
- processEnvironment(documents, thisDocument,
- &env, &processed);
+ if (! m_environment) {
+ Environment *env = new Environment(); // ### cache the environment.
+
+ QSet<QString> processed;
+ processEnvironment(m_thisDocument, env, &processed);
+ m_environment = QSharedPointer<Environment>(env);
+ }
+
const QByteArray code = expression.toUtf8();
- Preprocessor preproc(0, &env);
+ Preprocessor preproc(0, m_environment.data());
const QByteArray preprocessedCode = preproc("<expression>", code);
return QString::fromUtf8(preprocessedCode.constData(), preprocessedCode.size());
}
#include "CppDocument.h"
#include "LookupContext.h"
+#include "PreprocessorEnvironment.h"
#include <ASTfwd.h>
#include <QtCore/QMap>
class CPLUSPLUS_EXPORT TypeOfExpression
{
+ Q_DISABLE_COPY(TypeOfExpression)
+
public:
TypeOfExpression();
- Snapshot snapshot() const;
-
/**
* Sets the documents used to evaluate expressions. Should be set before
* calling this functor.
* Also clears the lookup context, so can be used to make sure references
* to the documents previously used are removed.
*/
- void setSnapshot(const Snapshot &documents);
+ void init(Document::Ptr thisDocument, const Snapshot &snapshot,
+ QSharedPointer<CreateBindings> bindings = QSharedPointer<CreateBindings>());
+
+ void reset();
enum PreprocessMode {
NoPreprocess,
* has been made!
*
* @param expression The expression to evaluate.
- * @param document The document the expression is part of.
- * @param lastVisibleSymbol The last visible symbol in the document.
+ * @param scope The scope enclosing the expression.
*/
- QList<LookupItem> operator()(const QString &expression, Document::Ptr document,
- Symbol *lastVisibleSymbol,
- PreprocessMode mode = NoPreprocess);
+ QList<LookupItem> operator()(const QString &expression,
+ Scope *scope,
+ PreprocessMode mode = NoPreprocess);
- QString preprocess(const QString &expression, Document::Ptr document) const;
+ QString preprocess(const QString &expression) const;
/**
* Returns the AST of the last evaluated expression.
/**
* Returns the lookup context of the last evaluated expression.
*/
- const LookupContext &lookupContext() const;
+ const LookupContext &context() const;
+ Scope *scope() const;
ExpressionAST *expressionAST() const;
ExpressionAST *extractExpressionAST(Document::Ptr doc) const;
Document::Ptr documentForExpression(const QString &expression) const;
- void processEnvironment(CPlusPlus::Snapshot documents,
- CPlusPlus::Document::Ptr doc, CPlusPlus::Environment *env,
+ void processEnvironment(Document::Ptr doc, Environment *env,
QSet<QString> *processed) const;
- QString preprocessedExpression(const QString &expression,
- CPlusPlus::Snapshot documents,
- CPlusPlus::Document::Ptr thisDocument) const;
+ QString preprocessedExpression(const QString &expression) const;
+private:
+ Document::Ptr m_thisDocument;
Snapshot m_snapshot;
+ QSharedPointer<CreateBindings> m_bindings;
ExpressionAST *m_ast;
+ Scope *m_scope;
LookupContext m_lookupContext;
+ mutable QSharedPointer<Environment> m_environment;
};
} // namespace CPlusPlus
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
-#ifndef TYPEPRETTYPRINTER_H
-#define TYPEPRETTYPRINTER_H
+#ifndef CPLUSPLUS_TYPEPRETTYPRINTER_H
+#define CPLUSPLUS_TYPEPRETTYPRINTER_H
#include <TypeVisitor.h>
#include <FullySpecifiedType.h>
} // end of namespace CPlusPlus
-#endif // TYPEPRETTYPRINTER_H
+#endif // CPLUSPLUS_TYPEPRETTYPRINTER_H
HEADERS += \
$$PWD/Icons.h \
$$PWD/ExpressionUnderCursor.h \
- $$PWD/TokenUnderCursor.h \
$$PWD/BackwardsScanner.h \
$$PWD/MatchingText.h \
- $$PWD/OverviewModel.h
+ $$PWD/OverviewModel.h \
+ $$PWD/TokenCache.h
SOURCES += \
$$PWD/Icons.cpp \
$$PWD/ExpressionUnderCursor.cpp \
- $$PWD/TokenUnderCursor.cpp \
$$PWD/BackwardsScanner.cpp \
$$PWD/MatchingText.cpp \
- $$PWD/OverviewModel.cpp
+ $$PWD/OverviewModel.cpp \
+ $$PWD/TokenCache.cpp
}
HEADERS += \
$$PWD/TypeOfExpression.h \
$$PWD/TypePrettyPrinter.h \
$$PWD/ResolveExpression.h \
+ $$PWD/LookupItem.h \
$$PWD/LookupContext.h \
- $$PWD/CppBindings.h \
$$PWD/ASTParent.h \
- $$PWD/GenTemplateInstance.h \
+ $$PWD/ASTPath.h \
+ $$PWD/DeprecatedGenTemplateInstance.h \
$$PWD/FindUsages.h \
$$PWD/CheckUndefinedSymbols.h \
$$PWD/DependencyTable.h \
$$PWD/TypeOfExpression.cpp \
$$PWD/TypePrettyPrinter.cpp \
$$PWD/ResolveExpression.cpp \
+ $$PWD/LookupItem.cpp \
$$PWD/LookupContext.cpp \
- $$PWD/CppBindings.cpp \
$$PWD/ASTParent.cpp \
- $$PWD/GenTemplateInstance.cpp \
+ $$PWD/ASTPath.cpp \
+ $$PWD/DeprecatedGenTemplateInstance.cpp \
$$PWD/FindUsages.cpp \
$$PWD/CheckUndefinedSymbols.cpp \
$$PWD/DependencyTable.cpp \
if (! env->isBuiltinMacro(spell)) {
Macro *m = env->resolve(spell);
if (m && ! m->isFunctionLike()) {
- QByteArray expandedDefinition;
- expandObjectLikeMacro(identifierToken, spell, m, &expandedDefinition);
- if (expandedDefinition.trimmed().isEmpty()) {
- out(QByteArray(spell.length(), ' '));
- continue;
- }
+ // expand object-like macros.
+ processObjectLikeMacro(identifierToken, spell, m);
+ continue;
}
}
out(spell);
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#ifndef PP_MACRO_EXPANDER_H
-#define PP_MACRO_EXPANDER_H
+#ifndef CPLUSPLUS_PP_MACRO_EXPANDER_H
+#define CPLUSPLUS_PP_MACRO_EXPANDER_H
#include "Macro.h"
#include "pp-scanner.h"
} // namespace CPlusPlus
-#endif // PP_MACRO_EXPANDER_H
+#endif // CPLUSPLUS_PP_MACRO_EXPANDER_H
case PluginSpec::Stopped:
text = tr("Stopped");
tooltip = tr("Plugin was shut down");
+ break;
case PluginSpec::Deleted:
text = tr("Deleted");
tooltip = tr("Plugin ended its life cycle and was deleted");
+ break;
}
+
m_ui->state->setText(text);
m_ui->state->setToolTip(tooltip);
m_ui->errorString->setText(spec->errorString());
$$PWD/qmljscheck.h \
$$PWD/qmljsscopebuilder.h \
$$PWD/qmljslineinfo.h \
- $$PWD/qmljscompletioncontextfinder.h
+ $$PWD/qmljscompletioncontextfinder.h \
+ $$PWD/qmljscomponentversion.h \
+ $$PWD/qmljsmodelmanagerinterface.h \
SOURCES += \
$$PWD/qmljsbind.cpp \
$$PWD/qmljscheck.cpp \
$$PWD/qmljsscopebuilder.cpp \
$$PWD/qmljslineinfo.cpp \
- $$PWD/qmljscompletioncontextfinder.cpp
+ $$PWD/qmljscompletioncontextfinder.cpp \
+ $$PWD/qmljscomponentversion.cpp \
+ $$PWD/qmljsmodelmanagerinterface.cpp
OTHER_FILES += \
$$PWD/parser/qmljs.g
{
}
-QStringList Bind::fileImports() const
+QList<Bind::ImportInfo> Bind::fileImports() const
{
return _fileImports;
}
-QStringList Bind::directoryImports() const
+QList<Bind::ImportInfo> Bind::directoryImports() const
{
return _directoryImports;
}
-QStringList Bind::libraryImports() const
+QList<Bind::ImportInfo> Bind::libraryImports() const
{
return _libraryImports;
}
bool Bind::visit(UiImport *ast)
{
+ ImportInfo info;
+
+ if (ast->versionToken.isValid()) {
+ const QString versionString = _doc->source().mid(ast->versionToken.offset, ast->versionToken.length);
+ const int dotIdx = versionString.indexOf(QLatin1Char('.'));
+ if (dotIdx != -1) {
+ info.version = ComponentVersion(versionString.left(dotIdx).toInt(),
+ versionString.mid(dotIdx + 1).toInt());
+ }
+ }
+
if (ast->importUri) {
- _libraryImports += toString(ast->importUri, QLatin1Char('/'));
+ info.name = toString(ast->importUri, QLatin1Char('/'));
+ _libraryImports += info;
} else if (ast->fileName) {
const QFileInfo importFileInfo(_doc->path() + QLatin1Char('/') + ast->fileName->asString());
+ info.name = importFileInfo.absoluteFilePath();
if (importFileInfo.isFile())
- _fileImports += importFileInfo.absoluteFilePath();
+ _fileImports += info;
else if (importFileInfo.isDir())
- _directoryImports += importFileInfo.absoluteFilePath();
+ _directoryImports += info;
//else
// error: file or directory does not exist
}
#include <qmljs/parser/qmljsastvisitor_p.h>
#include <qmljs/qmljsinterpreter.h>
+#include <qmljs/qmljscomponentversion.h>
#include <QtCore/QHash>
#include <QtCore/QStringList>
Bind(Document *doc);
virtual ~Bind();
- QStringList fileImports() const;
- QStringList directoryImports() const;
- QStringList libraryImports() const;
+ struct ImportInfo {
+ QString name;
+ ComponentVersion version;
+ };
+
+ QList<ImportInfo> fileImports() const;
+ QList<ImportInfo> directoryImports() const;
+ QList<ImportInfo> libraryImports() const;
Interpreter::ObjectValue *currentObjectValue() const;
Interpreter::ObjectValue *idEnvironment() const;
QHash<AST::FunctionDeclaration *, Interpreter::ObjectValue *> _functionScopes;
QStringList _includedScripts;
- QStringList _fileImports;
- QStringList _directoryImports;
- QStringList _libraryImports;
+ QList<ImportInfo> _fileImports;
+ QList<ImportInfo> _directoryImports;
+ QList<ImportInfo> _libraryImports;
};
} // end of namespace Qml
--- /dev/null
+#include "qmljscomponentversion.h"
+
+using namespace QmlJS;
+
+const int ComponentVersion::NoVersion = -1;
+
+ComponentVersion::ComponentVersion()
+ : _major(NoVersion), _minor(NoVersion)
+{
+}
+
+ComponentVersion::ComponentVersion(int major, int minor)
+ : _major(major), _minor(minor)
+{
+}
+
+ComponentVersion::~ComponentVersion()
+{
+}
+
+bool ComponentVersion::isValid() const
+{
+ return _major >= 0 && _minor >= 0;
+}
+
+namespace QmlJS {
+
+bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs)
+{
+ return lhs.major() < rhs.major()
+ || (lhs.major() == rhs.major() && lhs.minor() < rhs.minor());
+}
+
+bool operator<=(const ComponentVersion &lhs, const ComponentVersion &rhs)
+{
+ return lhs.major() < rhs.major()
+ || (lhs.major() == rhs.major() && lhs.minor() <= rhs.minor());
+}
+
+bool operator==(const ComponentVersion &lhs, const ComponentVersion &rhs)
+{
+ return lhs.major() == rhs.major() && lhs.minor() == rhs.minor();
+}
+
+bool operator!=(const ComponentVersion &lhs, const ComponentVersion &rhs)
+{
+ return !(lhs == rhs);
+}
+
+}
--- /dev/null
+#ifndef QMLJSCOMPONENTVERSION_H
+#define QMLJSCOMPONENTVERSION_H
+
+#include "qmljs_global.h"
+
+namespace QmlJS {
+
+class QMLJS_EXPORT ComponentVersion
+{
+ int _major;
+ int _minor;
+
+public:
+ static const int NoVersion;
+
+ ComponentVersion();
+ ComponentVersion(int major, int minor);
+ ~ComponentVersion();
+
+ int major() const
+ { return _major; }
+ int minor() const
+ { return _minor; }
+
+ // something in the GNU headers introduces the major() and minor() defines,
+ // use these two to disambiguate when necessary
+ int majorVersion() const
+ { return _major; }
+ int minorVersion() const
+ { return _minor; }
+
+ bool isValid() const;
+};
+
+bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs);
+bool operator<=(const ComponentVersion &lhs, const ComponentVersion &rhs);
+bool operator==(const ComponentVersion &lhs, const ComponentVersion &rhs);
+bool operator!=(const ComponentVersion &lhs, const ComponentVersion &rhs);
+
+} // namespace QmlJS
+
+#endif // QMLJSCOMPONENTVERSION_H
class Bind;
class Snapshot;
+namespace Interpreter {
+ class FakeMetaObject;
+}
+
class QMLJS_EXPORT Document
{
public:
bool _valid;
QList<QmlDirParser::Component> _components;
QList<QmlDirParser::Plugin> _plugins;
+ typedef QList<const Interpreter::FakeMetaObject *> FakeMetaObjectList;
+ FakeMetaObjectList _metaObjects;
public:
LibraryInfo();
QList<QmlDirParser::Plugin> plugins() const
{ return _plugins; }
+ FakeMetaObjectList metaObjects() const
+ { return _metaObjects; }
+
+ void setMetaObjects(const FakeMetaObjectList &objects)
+ { _metaObjects = objects; }
+
bool isValid() const
{ return _valid; }
};
#include "qmljsevaluate.h"
#include "qmljslink.h"
#include "qmljsscopebuilder.h"
+#include "qmljscomponentversion.h"
#include "parser/qmljsast_p.h"
#include <QtCore/QFile>
+#include <QtCore/QDir>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QMetaObject>
#include <QtCore/QMetaProperty>
#include <QtCore/QXmlStreamReader>
-#include <QtCore/QCoreApplication>
+#include <QtCore/QProcess>
#include <QtCore/QDebug>
using namespace QmlJS::Interpreter;
QString m_name;
QString m_package;
- int m_major;
- int m_minor;
+ QString m_packageNameVersion;
+ ComponentVersion m_version;
const FakeMetaObject *m_super;
QString m_superName;
QList<FakeMetaEnum> m_enums;
QString m_defaultPropertyName;
public:
- FakeMetaObject(const QString &name, const QString &package, int majorVersion, int minorVersion)
- : m_name(name), m_package(package), m_major(majorVersion), m_minor(minorVersion), m_super(0)
- {}
+ FakeMetaObject(const QString &name, const QString &package, ComponentVersion version)
+ : m_name(name), m_package(package), m_version(version), m_super(0)
+ {
+ m_packageNameVersion = QString::fromLatin1("%1.%2 %3.%4").arg(
+ package, name,
+ QString::number(version.majorVersion()), QString::number(version.minorVersion()));
+ }
void setSuperclassName(const QString &superclass)
{ m_superName = superclass; }
{ return m_name; }
QString packageName() const
{ return m_package; }
+ QString packageClassVersionString() const
+ { return m_packageNameVersion; }
void addEnum(const FakeMetaEnum &fakeEnum)
{ m_enumNameToIndex.insert(fakeEnum.name(), m_enums.size()); m_enums.append(fakeEnum); }
FakeMetaMethod method(int index) const
{ return m_methods.at(index); }
- int majorVersion() const
- { return m_major; }
- int minorVersion() const
- { return m_minor; }
+ ComponentVersion version() const
+ { return m_version; }
QString defaultPropertyName() const
{ return m_defaultPropertyName; }
public:
QmlXmlReader(QIODevice *dev)
: _xml(dev)
+ , _objects(0)
+ {}
+
+ QmlXmlReader(const QByteArray &data)
+ : _xml(data)
{}
bool operator()(QMap<QString, FakeMetaObject *> *objects) {
bool doInsert = true;
QString name, defaultPropertyName;
- int major = -1, minor = -1;
+ QmlJS::ComponentVersion version;
QString extends;
foreach (const QXmlStreamAttribute &attr, _xml.attributes()) {
if (attr.name() == QLatin1String("name")) {
return;
}
} else if (attr.name() == QLatin1String("version")) {
- QString version = attr.value().toString();
- int dotIdx = version.indexOf('.');
+ QString versionStr = attr.value().toString();
+ int dotIdx = versionStr.indexOf('.');
if (dotIdx == -1) {
bool ok = false;
- major = version.toInt(&ok);
+ const int major = versionStr.toInt(&ok);
if (!ok) {
- invalidAttr(version, QLatin1String("version"), tag);
+ invalidAttr(versionStr, QLatin1String("version"), tag);
return;
}
- minor = -1;
+ version = QmlJS::ComponentVersion(major, QmlJS::ComponentVersion::NoVersion);
} else {
bool ok = false;
- major = version.left(dotIdx).toInt(&ok);
+ const int major = versionStr.left(dotIdx).toInt(&ok);
if (!ok) {
- invalidAttr(version, QLatin1String("version"), tag);
+ invalidAttr(versionStr, QLatin1String("version"), tag);
return;
}
- minor = version.mid(dotIdx + 1).toInt(&ok);
+ const int minor = versionStr.mid(dotIdx + 1).toInt(&ok);
if (!ok) {
- invalidAttr(version, QLatin1String("version"), tag);
+ invalidAttr(versionStr, QLatin1String("version"), tag);
return;
}
+ version = QmlJS::ComponentVersion(major, minor);
}
} else if (attr.name() == QLatin1String("defaultProperty")) {
defaultPropertyName = attr.value().toString();
QString className, packageName;
split(name, &packageName, &className);
- FakeMetaObject *metaObject = new FakeMetaObject(className, packageName,
- major, minor);
+ FakeMetaObject *metaObject = new FakeMetaObject(className, packageName, version);
if (! extends.isEmpty())
metaObject->setSuperclassName(extends);
if (! defaultPropertyName.isEmpty())
} // end of anonymous namespace
-const int QmlObjectValue::NoVersion = -1;
-
QmlObjectValue::QmlObjectValue(const FakeMetaObject *metaObject, Engine *engine)
: ObjectValue(engine),
_metaObject(metaObject)
const QString typeName = prop.typeName();
// ### Verify type resolving.
- QmlObjectValue *objectValue = engine()->metaTypeSystem().staticTypeForImport(typeName);
+ QmlObjectValue *objectValue = engine()->cppQmlTypes().typeForImport(typeName);
if (objectValue)
return objectValue;
QString QmlObjectValue::packageName() const
{ return _metaObject->packageName(); }
-int QmlObjectValue::majorVersion() const
-{ return _metaObject->majorVersion(); }
-
-int QmlObjectValue::minorVersion() const
-{ return _metaObject->minorVersion(); }
+QmlJS::ComponentVersion QmlObjectValue::version() const
+{ return _metaObject->version(); }
QString QmlObjectValue::defaultPropertyName() const
{ return _metaObject->defaultPropertyName(); }
return false;
}
+// Returns true if this object is in a package or if there is an object that
+// has this one in its prototype chain and is itself in a package.
+bool QmlObjectValue::hasChildInPackage() const
+{
+ if (!packageName().isEmpty())
+ return true;
+ QHashIterator<QString, QmlObjectValue *> it(engine()->cppQmlTypes().types());
+ while (it.hasNext()) {
+ it.next();
+ const FakeMetaObject *other = it.value()->_metaObject;
+ if (other->packageName().isEmpty())
+ continue;
+ for (const FakeMetaObject *iter = other; iter; iter = iter->superClass()) {
+ if (iter == _metaObject) // this object is a parent of other
+ return true;
+ }
+ }
+ return false;
+}
+
bool QmlObjectValue::isDerivedFrom(const FakeMetaObject *base) const
{
for (const FakeMetaObject *iter = _metaObject; iter; iter = iter->superClass()) {
const ObjectValue *Context::lookupType(const QmlJS::Document *doc, const QStringList &qmlTypeName)
{
const ObjectValue *objectValue = typeEnvironment(doc);
- if (!objectValue)
- return 0;
foreach (const QString &name, qmlTypeName) {
+ if (!objectValue)
+ return 0;
+
const Value *value = objectValue->property(name, this);
if (!value)
return 0;
// typing environment
////////////////////////////////////////////////////////////////////////////////
-QList<const FakeMetaObject *> MetaTypeSystem::_metaObjects;
+QList<const FakeMetaObject *> CppQmlTypesLoader::builtinObjects;
-QStringList MetaTypeSystem::load(const QFileInfoList &xmlFiles)
+QStringList CppQmlTypesLoader::load(const QFileInfoList &xmlFiles)
{
- QMap<QString, FakeMetaObject *> objects;
-
+ QMap<QString, FakeMetaObject *> newObjects;
QStringList errorMsgs;
foreach (const QFileInfo &xmlFile, xmlFiles) {
QFile file(xmlFile.absoluteFilePath());
if (file.open(QIODevice::ReadOnly)) {
QmlXmlReader read(&file);
- if (!read(&objects)) {
+ if (!read(&newObjects)) {
errorMsgs.append(read.errorMessage());
}
file.close();
}
if (errorMsgs.isEmpty()) {
- qDeleteAll(_metaObjects);
- _metaObjects.clear();
-
- foreach (FakeMetaObject *obj, objects.values()) {
- const QString superName = obj->superclassName();
- if (! superName.isEmpty()) {
- obj->setSuperclass(objects.value(superName, 0));
- }
- _metaObjects.append(obj);
+ setSuperClasses(&newObjects);
+
+ // we need to go from QList<T *> of newObjects.values() to QList<const T *>
+ // and there seems to be no better way
+ QMapIterator<QString, FakeMetaObject *> it(newObjects);
+ while (it.hasNext()) {
+ it.next();
+ builtinObjects.append(it.value());
}
}
return errorMsgs;
}
-void MetaTypeSystem::reload(Engine *interpreter)
+QString CppQmlTypesLoader::parseQmlTypeXml(const QByteArray &xml, QMap<QString, FakeMetaObject *> *newObjects)
+{
+ QmlXmlReader reader(xml);
+ if (!reader(newObjects)) {
+ if (reader.errorMessage().isEmpty())
+ return QLatin1String("unknown error");
+ return reader.errorMessage();
+ }
+ setSuperClasses(newObjects);
+ return QString();
+}
+
+void CppQmlTypesLoader::setSuperClasses(QMap<QString, FakeMetaObject *> *newObjects)
+{
+ QMapIterator<QString, FakeMetaObject *> it(*newObjects);
+ while (it.hasNext()) {
+ it.next();
+ FakeMetaObject *obj = it.value();
+
+ const QString superName = obj->superclassName();
+ if (! superName.isEmpty()) {
+ FakeMetaObject *superClass = newObjects->value(superName);
+ if (superClass)
+ obj->setSuperclass(superClass);
+ else
+ qWarning() << "QmlJS::Interpreter::MetaTypeSystem: Can't find superclass" << superName << "for" << it.key();
+ }
+ }
+}
+
+void CppQmlTypes::load(Engine *engine, const QList<const FakeMetaObject *> &objects)
{
- QHash<const FakeMetaObject *, QmlObjectValue *> qmlObjects;
- _importedTypes.clear();
+ // load
+ foreach (const FakeMetaObject *metaObject, objects) {
+ // make sure we're not loading duplicate objects
+ if (_typesByFullyQualifiedName.contains(metaObject->packageClassVersionString()))
+ continue;
- foreach (const FakeMetaObject *metaObject, _metaObjects) {
- QmlObjectValue *objectValue = new QmlObjectValue(metaObject, interpreter);
- qmlObjects.insert(metaObject, objectValue);
- _importedTypes[metaObject->packageName()].append(objectValue);
+ QmlObjectValue *objectValue = new QmlObjectValue(metaObject, engine);
+ _typesByPackage[metaObject->packageName()].append(objectValue);
+ _typesByFullyQualifiedName[metaObject->packageClassVersionString()] = objectValue;
}
- foreach (const FakeMetaObject *metaObject, _metaObjects) {
- QmlObjectValue *objectValue = qmlObjects.value(metaObject);
- if (!objectValue)
+ // set prototype correctly
+ foreach (const FakeMetaObject *metaObject, objects) {
+ QmlObjectValue *objectValue = _typesByFullyQualifiedName.value(metaObject->packageClassVersionString());
+ if (!objectValue || !metaObject->superClass())
continue;
- objectValue->setPrototype(qmlObjects.value(metaObject->superClass(), 0));
+ objectValue->setPrototype(_typesByFullyQualifiedName.value(metaObject->superClass()->packageClassVersionString()));
}
}
-QList<QmlObjectValue *> MetaTypeSystem::staticTypesForImport(const QString &packageName, int majorVersion, int minorVersion) const
+QList<QmlObjectValue *> CppQmlTypes::typesForImport(const QString &packageName, QmlJS::ComponentVersion version) const
{
QMap<QString, QmlObjectValue *> objectValuesByName;
- foreach (QmlObjectValue *qmlObjectValue, _importedTypes.value(packageName)) {
- if (qmlObjectValue->majorVersion() < majorVersion ||
- (qmlObjectValue->majorVersion() == majorVersion && qmlObjectValue->minorVersion() <= minorVersion)) {
+ foreach (QmlObjectValue *qmlObjectValue, _typesByPackage.value(packageName)) {
+ if (qmlObjectValue->version() <= version) {
// we got a candidate.
const QString typeName = qmlObjectValue->className();
QmlObjectValue *previousCandidate = objectValuesByName.value(typeName, 0);
if (previousCandidate) {
// check if our new candidate is newer than the one we found previously
- if (qmlObjectValue->majorVersion() > previousCandidate->majorVersion() ||
- (qmlObjectValue->majorVersion() == previousCandidate->majorVersion() && qmlObjectValue->minorVersion() > previousCandidate->minorVersion())) {
+ if (previousCandidate->version() < qmlObjectValue->version()) {
// the new candidate has a higher version no. than the one we found previously, so replace it
objectValuesByName.insert(typeName, qmlObjectValue);
}
return objectValuesByName.values();
}
-QmlObjectValue *MetaTypeSystem::staticTypeForImport(const QString &qualifiedName) const
+QmlObjectValue *CppQmlTypes::typeForImport(const QString &qualifiedName) const
{
QString name = qualifiedName;
QString packageName;
}
QmlObjectValue *previousCandidate = 0;
- foreach (QmlObjectValue *qmlObjectValue, _importedTypes.value(packageName)) {
+ foreach (QmlObjectValue *qmlObjectValue, _typesByPackage.value(packageName)) {
const QString typeName = qmlObjectValue->className();
if (typeName != name)
continue;
if (previousCandidate) {
// check if our new candidate is newer than the one we found previously
- if (qmlObjectValue->majorVersion() > previousCandidate->majorVersion() ||
- (qmlObjectValue->majorVersion() == previousCandidate->majorVersion() && qmlObjectValue->minorVersion() > previousCandidate->minorVersion())) {
+ if (previousCandidate->version() < qmlObjectValue->version()) {
// the new candidate has a higher version no. than the one we found previously, so replace it
previousCandidate = qmlObjectValue;
}
return previousCandidate;
}
-bool MetaTypeSystem::hasPackage(const QString &package) const
+bool CppQmlTypes::hasPackage(const QString &package) const
{
- return _importedTypes.contains(package);
+ return _typesByPackage.contains(package);
}
ConvertToNumber::ConvertToNumber(Engine *engine)
{
initializePrototypes();
- _metaTypeSystem.reload(this);
+ _cppQmlTypes.load(this, CppQmlTypesLoader::builtinObjects);
}
Engine::~Engine()
#include <qmljs/qmljsdocument.h>
#include <qmljs/qmljs_global.h>
+#include <qmljs/qmljscomponentversion.h>
#include <qmljs/parser/qmljsastfwd_p.h>
#include <QtCore/QFileInfoList>
class QMLJS_EXPORT QmlObjectValue: public ObjectValue
{
public:
- static const int NoVersion;
-
-public:
QmlObjectValue(const FakeMetaObject *metaObject, Engine *engine);
virtual ~QmlObjectValue();
const Value *propertyValue(const FakeMetaProperty &prop) const;
QString packageName() const;
- int majorVersion() const;
- int minorVersion() const;
+ ComponentVersion version() const;
QString defaultPropertyName() const;
QString propertyType(const QString &propertyName) const;
bool isListProperty(const QString &name) const;
bool isEnum(const QString &typeName) const;
bool enumContainsKey(const QString &enumName, const QString &enumKeyName) const;
+ bool hasChildInPackage() const;
protected:
const Value *findOrCreateSignature(int index, const FakeMetaMethod &method, QString *methodName) const;
// typing environment
////////////////////////////////////////////////////////////////////////////////
-class QMLJS_EXPORT MetaTypeSystem
+class QMLJS_EXPORT CppQmlTypesLoader
{
- static QList<const FakeMetaObject *> _metaObjects;
-
public:
/** \return an empty list when successful, error messages otherwise. */
static QStringList load(const QFileInfoList &xmlFiles);
+ static QList<const FakeMetaObject *> builtinObjects;
- void reload(Interpreter::Engine *interpreter);
+ // parses the xml string and fills the newObjects map
+ static QString parseQmlTypeXml(const QByteArray &xml, QMap<QString, FakeMetaObject *> *newObjects);
+private:
+ static void setSuperClasses(QMap<QString, FakeMetaObject *> *newObjects);
+};
- QList<Interpreter::QmlObjectValue *> staticTypesForImport(const QString &prefix, int majorVersion, int minorVersion) const;
- Interpreter::QmlObjectValue *staticTypeForImport(const QString &qualifiedName) const;
+class QMLJS_EXPORT CppQmlTypes
+{
+public:
+ void load(Interpreter::Engine *interpreter, const QList<const FakeMetaObject *> &objects);
+
+ QList<Interpreter::QmlObjectValue *> typesForImport(const QString &prefix, ComponentVersion version) const;
+ Interpreter::QmlObjectValue *typeForImport(const QString &qualifiedName) const;
bool hasPackage(const QString &package) const;
+ QHash<QString, QmlObjectValue *> types() const
+ { return _typesByFullyQualifiedName; }
+
private:
- QHash<QString, QList<QmlObjectValue *> > _importedTypes;
+ QHash<QString, QList<QmlObjectValue *> > _typesByPackage;
+ QHash<QString, QmlObjectValue *> _typesByFullyQualifiedName;
};
class ConvertToNumber: protected ValueVisitor // ECMAScript ToInt()
QString typeId(const Value *value);
// typing:
- const MetaTypeSystem &metaTypeSystem() const
- { return _metaTypeSystem; }
+ CppQmlTypes &cppQmlTypes()
+ { return _cppQmlTypes; }
+ const CppQmlTypes &cppQmlTypes() const
+ { return _cppQmlTypes; }
void registerValue(Value *value); // internal
ConvertToObject _convertToObject;
TypeId _typeId;
- MetaTypeSystem _metaTypeSystem;
+ CppQmlTypes _cppQmlTypes;
};
} else {
// add scope chains for all components that import this file
foreach (Document::Ptr otherDoc, _snapshot) {
- foreach (const QString &fileImport, otherDoc->bind()->fileImports()) {
- if (_doc->fileName() == fileImport) {
+ foreach (const Bind::ImportInfo &fileImport, otherDoc->bind()->fileImports()) {
+ if (_doc->fileName() == fileImport.name) {
ScopeChain::QmlComponentChain *component = new ScopeChain::QmlComponentChain;
componentScopes.insert(otherDoc.data(), component);
scopeChain.qmlComponentScope.instantiatingComponents += component;
return;
// Add the implicitly available Script type
- const ObjectValue *scriptValue = engine()->metaTypeSystem().staticTypeForImport("Script");
+ const ObjectValue *scriptValue = engine()->cppQmlTypes().typeForImport("Script");
if (scriptValue)
typeEnv->setProperty("Script", scriptValue);
}
const QString packageName = Bind::toString(import->importUri, '.');
- int majorVersion = QmlObjectValue::NoVersion;
- int minorVersion = QmlObjectValue::NoVersion;
+ ComponentVersion version;
if (import->versionToken.isValid()) {
const QString versionString = doc->source().mid(import->versionToken.offset, import->versionToken.length);
tr("expected two numbers separated by a dot"));
return;
} else {
- majorVersion = versionString.left(dotIdx).toInt();
- minorVersion = versionString.mid(dotIdx + 1).toInt();
+ const int majorVersion = versionString.left(dotIdx).toInt();
+ const int minorVersion = versionString.mid(dotIdx + 1).toInt();
+ version = ComponentVersion(majorVersion, minorVersion);
}
} else {
error(doc, locationFromRange(import->firstSourceLocation(), import->lastSourceLocation()),
return;
}
- // if the package is in the meta type system, use it
- if (engine()->metaTypeSystem().hasPackage(packageName)) {
- foreach (QmlObjectValue *object, engine()->metaTypeSystem().staticTypesForImport(packageName, majorVersion, minorVersion)) {
- namespaceObject->setProperty(object->className(), object);
- }
- return;
- } else {
- // check the filesystem
- const QString packagePath = Bind::toString(import->importUri, QDir::separator());
- foreach (const QString &importPath, _importPaths) {
- QDir dir(importPath);
- if (!dir.cd(packagePath))
- continue;
+ bool importFound = false;
- const LibraryInfo libraryInfo = _snapshot.libraryInfo(dir.path());
- if (!libraryInfo.isValid())
- continue;
+ // check the filesystem
+ const QString packagePath = Bind::toString(import->importUri, QDir::separator());
+ foreach (const QString &importPath, _importPaths) {
+ QDir dir(importPath);
+ if (!dir.cd(packagePath))
+ continue;
- if (!libraryInfo.plugins().isEmpty())
- _context->setDocumentImportsPlugins(doc.data());
+ const LibraryInfo libraryInfo = _snapshot.libraryInfo(dir.path());
+ if (!libraryInfo.isValid())
+ continue;
- QSet<QString> importedTypes;
- foreach (const QmlDirParser::Component &component, libraryInfo.components()) {
- if (importedTypes.contains(component.typeName))
- continue;
+ importFound = true;
- if (component.majorVersion > majorVersion
- || (component.majorVersion == majorVersion
- && component.minorVersion > minorVersion))
- continue;
+ if (!libraryInfo.plugins().isEmpty())
+ engine()->cppQmlTypes().load(engine(), libraryInfo.metaObjects());
- importedTypes.insert(component.typeName);
- if (Document::Ptr importedDoc = _snapshot.document(dir.filePath(component.fileName))) {
- if (importedDoc->bind()->rootObjectValue())
- namespaceObject->setProperty(component.typeName, importedDoc->bind()->rootObjectValue());
- }
+ QSet<QString> importedTypes;
+ foreach (const QmlDirParser::Component &component, libraryInfo.components()) {
+ if (importedTypes.contains(component.typeName))
+ continue;
+
+ ComponentVersion componentVersion(component.majorVersion, component.minorVersion);
+ if (version < componentVersion)
+ continue;
+
+ importedTypes.insert(component.typeName);
+ if (Document::Ptr importedDoc = _snapshot.document(dir.filePath(component.fileName))) {
+ if (importedDoc->bind()->rootObjectValue())
+ namespaceObject->setProperty(component.typeName, importedDoc->bind()->rootObjectValue());
}
+ }
- return;
+ break;
+ }
+
+ // if there are cpp-based types for this package, use them too
+ if (engine()->cppQmlTypes().hasPackage(packageName)) {
+ importFound = true;
+ foreach (QmlObjectValue *object, engine()->cppQmlTypes().typesForImport(packageName, version)) {
+ namespaceObject->setProperty(object->className(), object);
}
}
- error(doc, locationFromRange(import->firstSourceLocation(), import->lastSourceLocation()),
- tr("package not found"));
+ if (!importFound) {
+ error(doc, locationFromRange(import->firstSourceLocation(), import->lastSourceLocation()),
+ tr("package not found"));
+ }
}
UiQualifiedId *Link::qualifiedTypeNameId(Node *node)
#include "qmljsmodelmanagerinterface.h"
-using namespace QmlJSEditor;
+using namespace QmlJS;
-ModelManagerInterface::ModelManagerInterface(QObject *parent):
- QObject(parent)
+ModelManagerInterface::ModelManagerInterface(QObject *parent)
+ : QObject(parent)
{
}
ModelManagerInterface::~ModelManagerInterface()
{
}
+
#ifndef QMLJSMODELMANAGERINTERFACE_H
#define QMLJSMODELMANAGERINTERFACE_H
-#include "qmljseditor_global.h"
-
-#include <qmljs/qmljsdocument.h>
+#include "qmljs_global.h"
+#include "qmljsdocument.h"
#include <QObject>
#include <QStringList>
#include <QSharedPointer>
namespace QmlJS {
-class Snapshot;
-}
-namespace QmlJSEditor {
+class Snapshot;
-class QMLJSEDITOR_EXPORT ModelManagerInterface: public QObject
+class QMLJS_EXPORT ModelManagerInterface: public QObject
{
Q_OBJECT
void aboutToRemoveFiles(const QStringList &files);
};
-} // namespace QmlJSEditor
+} // namespace QmlJS
#endif // QMLJSMODELMANAGERINTERFACE_H
}
Scanner::Scanner()
- : _state(0),
+ : _state(Normal),
_scanComments(true)
{
}
QList<Token> Scanner::operator()(const QString &text, int startState)
{
- enum {
- Normal = 0,
- MultiLineComment = 1
- };
-
_state = startState;
QList<Token> tokens;
class QMLJS_EXPORT Scanner
{
public:
+ enum {
+ Normal = 0,
+ MultiLineComment = 1
+ };
+
Scanner();
virtual ~Scanner();
bool scanComments() const;
void setScanComments(bool scanComments);
- QList<Token> operator()(const QString &text, int startState = 0);
+ QList<Token> operator()(const QString &text, int startState = Normal);
int state() const;
bool isKeyword(const QString &text) const;
/* A messagebox suitable for questions with a
* "Do not ask me again" checkbox. Emulates the QMessageBox API with
- * static conveniences. */
+ * static conveniences. The message label can open external URLs. */
class QTCREATOR_UTILS_EXPORT CheckableMessageBox : public QDialog
{
<ui version="4.0">
<class>Utils::CheckableMessageBox</class>
<widget class="QDialog" name="Utils::CheckableMessageBox">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>195</width>
- <height>107</height>
- </rect>
- </property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
- <widget class="QLabel" name="pixmapLabel"/>
+ <widget class="QLabel" name="pixmapLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
</item>
<item>
<spacer name="pixmapSpacer">
</item>
<item>
<widget class="QLabel" name="messageLabel">
+ <property name="minimumSize">
+ <size>
+ <width>300</width>
+ <height>0</height>
+ </size>
+ </property>
<property name="text">
- <string>TextLabel</string>
+ <string notr="true">dummyText</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox">
<property name="text">
- <string>CheckBox</string>
+ <string notr="true">CheckBox</string>
</property>
</widget>
</item>
// in the following way:
//
// +------------+-------------------------+---------------+
- // + toolWidget | summaryLabel | detailsButton |
+ // +summaryLabel| toolwidget | detailsButton |
// +------------+-------------------------+---------------+
- // | | widget |
+ // | widget |
// +------------+-------------------------+---------------+
struct DetailsWidgetPrivate {
d->m_grid->setContentsMargins(0, 0, 0, 0);
d->m_grid->setSpacing(0);
- d->m_grid->addWidget(d->m_summaryLabel, 0, 1);
+ d->m_grid->addWidget(d->m_summaryLabel, 0, 0);
d->m_grid->addWidget(d->m_detailsButton, 0, 2);
setLayout(d->m_grid);
if (d->m_widget) {
d->m_widget->setContentsMargins(MARGIN, MARGIN, MARGIN, MARGIN);
- d->m_grid->addWidget(d->m_widget, 1, 1, 1, 2);
+ d->m_grid->addWidget(d->m_widget, 1, 0, 1, 3);
}
updateControls();
}
d->m_toolWidget->adjustSize();
d->m_grid->addWidget(d->m_toolWidget, 0, 1, 1, 1, Qt::AlignRight);
- d->m_grid->setColumnMinimumWidth(0, d->m_toolWidget->width());
- d->m_grid->setRowMinimumHeight(0, d->m_toolWidget->height());
-
changeHoverState(d->m_hovered);
}
while (startOfLastLine[i] != '\n' && startOfLastLine[i] != '\r' && i < textLength && n++ < 256)
res.append(startOfLastLine[i++]);
future.reportResult(FileSearchResult(s, lineNr, QString(res),
- regionPtr - startOfLastLine, sa.length()));
+ regionPtr - startOfLastLine, sa.length(),
+ QStringList()));
++numMatches;
}
}
int pos = 0;
while ((pos = expression.indexIn(line, pos)) != -1) {
future.reportResult(FileSearchResult(s, lineNr, line,
- pos, expression.matchedLength()));
+ pos, expression.matchedLength(),
+ expression.capturedTexts()));
pos += expression.matchedLength();
}
++lineNr;
return QtConcurrent::run<FileSearchResult, QString, QStringList, QTextDocument::FindFlags, QMap<QString, QString> >
(runFileSearchRegExp, searchTerm, files, flags, fileToContentsMap);
}
+
+QString Utils::expandRegExpReplacement(const QString &replaceText, const QStringList &capturedTexts)
+{
+ QString result;
+ int numCaptures = capturedTexts.size() - 1;
+ for (int i = 0; i < replaceText.length(); ++i) {
+ QChar c = replaceText.at(i);
+ if (c == QLatin1Char('\\') && i < replaceText.length() - 1) {
+ c = replaceText.at(++i);
+ if (c == QLatin1Char('\\')) {
+ result += QLatin1Char('\\');
+ } else if (c == QLatin1Char('&')) {
+ result += QLatin1Char('&');
+ } else if (c.isDigit()) {
+ int index = c.unicode()-'1';
+ if (index < numCaptures) {
+ result += capturedTexts.at(index+1);
+ } else {
+ result += QLatin1Char('\\');
+ result += c;
+ }
+ } else {
+ result += QLatin1Char('\\');
+ result += c;
+ }
+ } else if (c == QLatin1Char('&')) {
+ result += capturedTexts.at(0);
+ } else {
+ result += c;
+ }
+ }
+ return result;
+}
{
public:
FileSearchResult() {}
- FileSearchResult(QString fileName, int lineNumber, QString matchingLine, int matchStart, int matchLength)
- : fileName(fileName), lineNumber(lineNumber), matchingLine(matchingLine), matchStart(matchStart), matchLength(matchLength)
+ FileSearchResult(QString fileName, int lineNumber, QString matchingLine,
+ int matchStart, int matchLength,
+ QStringList regexpCapturedTexts)
+ : fileName(fileName),
+ lineNumber(lineNumber),
+ matchingLine(matchingLine),
+ matchStart(matchStart),
+ matchLength(matchLength),
+ regexpCapturedTexts(regexpCapturedTexts)
{
}
QString fileName;
QString matchingLine;
int matchStart;
int matchLength;
+ QStringList regexpCapturedTexts;
};
QTCREATOR_UTILS_EXPORT QFuture<FileSearchResult> findInFiles(const QString &searchTerm, const QStringList &files,
QTCREATOR_UTILS_EXPORT QFuture<FileSearchResult> findInFilesRegExp(const QString &searchTerm, const QStringList &files,
QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap = QMap<QString, QString>());
+QTCREATOR_UTILS_EXPORT QString expandRegExpReplacement(const QString &replaceText, const QStringList &capturedTexts);
+
} // namespace Utils
#endif // FILESEARCH_H
perror("Cannot create creator comm socket");
doExit(3);
}
+ memset(&sau, 0, sizeof(sau));
sau.sun_family = AF_UNIX;
- strcpy(sau.sun_path, argv[ArgSocket]);
+ strncpy(sau.sun_path, argv[ArgSocket], sizeof(sau.sun_path) - 1);
if (connect(qtcFd, (struct sockaddr *)&sau, sizeof(sau))) {
fprintf(stderr, "Cannot connect creator comm socket %s: %s\n", sau.sun_path, strerror(errno));
doExit(1);
fseek(envFd, 0, SEEK_END);
size = ftell(envFd);
rewind(envFd);
- envdata = malloc(size);
+ envdata = malloc(size + sizeof(char *));
+ envdata[size] = 0;
if (fread(envdata, 1, size, envFd) != (size_t)size) {
perror("Failed to read env file");
doExit(1);
fseek(envFd, 0, SEEK_END);
size = ftell(envFd);
rewind(envFd);
- env = malloc(size);
+ env = malloc(size + sizeof(wchar_t));
+ env[size] = 0;
if (fread(env, 1, size, envFd) != size) {
perror("Failed to read env file");
doExit(1);
lastSeparatorPos = common.lastIndexOf(QLatin1Char('\\'));
if (lastSeparatorPos == -1)
return QString();
- if (lastSeparatorPos == -1)
- return QString();
#ifdef Q_OS_UNIX
if (lastSeparatorPos == 0) // Unix: "/a", "/b" -> '/'
lastSeparatorPos = 1;
QLinearGradient shadowGradient(spanRect.topLeft(), spanRect.topRight());
shadowGradient.setColorAt(0, QColor(0, 0, 0, 30));
QColor lighterHighlight;
- if (!lightColored)
- lighterHighlight = highlight.lighter(130);
- else
- lighterHighlight = highlight.lighter(90);
+ lighterHighlight = highlight.lighter(130);
lighterHighlight.setAlpha(100);
shadowGradient.setColorAt(0.7, lighterHighlight);
shadowGradient.setColorAt(1, QColor(0, 0, 0, 40));
#include <QtCore/QTextCodec>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
+#include <QtGui/QMessageBox>
#include <QtGui/QApplication>
#include <limits.h>
+#ifdef Q_OS_UNIX
+# include <unistd.h>
+#endif
+
enum { debug = 0 };
enum { syncDebug = 0 };
namespace Utils {
+// A special QProcess derivative allowing for terminal control.
+class TerminalControllingProcess : public QProcess {
+public:
+ TerminalControllingProcess() : m_flags(0) {}
+
+ unsigned flags() const { return m_flags; }
+ void setFlags(unsigned tc) { m_flags = tc; }
+
+protected:
+ virtual void setupChildProcess();
+
+private:
+ unsigned m_flags;
+};
+
+void TerminalControllingProcess::setupChildProcess()
+{
+#ifdef Q_OS_UNIX
+ // Disable terminal by becoming a session leader.
+ if (m_flags & SynchronousProcess::UnixTerminalDisabled)
+ setsid();
+#endif
+}
+
// ----------- SynchronousProcessResponse
SynchronousProcessResponse::SynchronousProcessResponse() :
result(StartFailed),
stdErr.clear();
}
+QString SynchronousProcessResponse::exitMessage(const QString &binary, int timeoutMS) const
+{
+ switch (result) {
+ case Finished:
+ return SynchronousProcess::tr("The command '%1' finished successfully.").arg(binary);
+ case FinishedError:
+ return SynchronousProcess::tr("The command '%1' terminated with exit code %2.").arg(binary).arg(exitCode);
+ break;
+ case TerminatedAbnormally:
+ return SynchronousProcess::tr("The command '%1' terminated abnormally.").arg(binary);
+ case StartFailed:
+ return SynchronousProcess::tr("The command '%1' could not be started.").arg(binary);
+ case Hang:
+ return SynchronousProcess::tr("The command '%1' did not respond within the timeout limit (%2 ms).").
+ arg(binary).arg(timeoutMS);
+ }
+ return QString();
+}
+
QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse& r)
{
QDebug nsp = str.nospace();
void clearForRun();
QTextCodec *m_stdOutCodec;
- QProcess m_process;
+ TerminalControllingProcess m_process;
QTimer m_timer;
QEventLoop m_eventLoop;
SynchronousProcessResponse m_result;
int m_hangTimerCount;
int m_maxHangTimerCount;
bool m_startFailure;
+ bool m_timeOutMessageBoxEnabled;
+ QString m_binary;
ChannelBuffer m_stdOut;
ChannelBuffer m_stdErr;
m_stdOutCodec(0),
m_hangTimerCount(0),
m_maxHangTimerCount(defaultMaxHangTimerCount),
- m_startFailure(false)
+ m_startFailure(false),
+ m_timeOutMessageBoxEnabled(false)
{
}
m_stdErr.clearForRun();
m_result.clear();
m_startFailure = false;
+ m_binary.clear();
}
// ----------- SynchronousProcess
return m_d->m_process.environment();
}
+bool SynchronousProcess::timeOutMessageBoxEnabled() const
+{
+ return m_d->m_timeOutMessageBoxEnabled;
+}
+
+void SynchronousProcess::setTimeOutMessageBoxEnabled(bool v)
+{
+ m_d->m_timeOutMessageBoxEnabled = v;
+}
+
void SynchronousProcess::setEnvironment(const QStringList &e)
{
m_d->m_process.setEnvironment(e);
return m_d->m_process.processEnvironment();
}
+unsigned SynchronousProcess::flags() const
+{
+ return m_d->m_process.flags();
+}
+
+void SynchronousProcess::setFlags(unsigned tc)
+{
+ m_d->m_process.setFlags(tc);
+}
+
void SynchronousProcess::setWorkingDirectory(const QString &workingDirectory)
{
m_d->m_process.setWorkingDirectory(workingDirectory);
// On Windows, start failure is triggered immediately if the
// executable cannot be found in the path. Do not start the
// event loop in that case.
+ m_d->m_binary = binary;
m_d->m_process.start(binary, args, QIODevice::ReadOnly);
if (!m_d->m_startFailure) {
m_d->m_timer.start();
return m_d->m_result;
}
+static inline bool askToKill(const QString &binary = QString())
+{
+ const QString title = SynchronousProcess::tr("Process not Responding");
+ QString msg = binary.isEmpty() ?
+ SynchronousProcess::tr("The process is not responding.") :
+ SynchronousProcess::tr("The process '%1' is not responding.").arg(binary);
+ msg += QLatin1Char(' ');
+ msg += SynchronousProcess::tr(" Would you like to terminate it?");
+ // Restore the cursor that is set to wait while running.
+ const bool hasOverrideCursor = QApplication::overrideCursor() != 0;
+ if (hasOverrideCursor)
+ QApplication::restoreOverrideCursor();
+ QMessageBox::StandardButton answer = QMessageBox::question(0, title, msg, QMessageBox::Yes|QMessageBox::No);
+ if (hasOverrideCursor)
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ return answer == QMessageBox::Yes;
+}
+
void SynchronousProcess::slotTimeout()
{
if (++m_d->m_hangTimerCount > m_d->m_maxHangTimerCount) {
if (debug)
qDebug() << Q_FUNC_INFO << "HANG detected, killing";
- SynchronousProcess::stopProcess(m_d->m_process);
- m_d->m_result.result = SynchronousProcessResponse::Hang;
+ const bool terminate = !m_d->m_timeOutMessageBoxEnabled || askToKill(m_d->m_binary);
+ if (terminate) {
+ SynchronousProcess::stopProcess(m_d->m_process);
+ m_d->m_result.result = SynchronousProcessResponse::Hang;
+ } else {
+ m_d->m_hangTimerCount = 0;
+ }
} else {
if (debug)
qDebug() << Q_FUNC_INFO << m_d->m_hangTimerCount;
}
}
+QSharedPointer<QProcess> SynchronousProcess::createProcess(unsigned flags)
+{
+ TerminalControllingProcess *process = new TerminalControllingProcess;
+ process->setFlags(flags);
+ return QSharedPointer<QProcess>(process);
+}
+
// Static utilities: Keep running as long as it gets data.
bool SynchronousProcess::readDataFromProcess(QProcess &p, int timeOutMS,
- QByteArray *stdOut, QByteArray *stdErr)
+ QByteArray *stdOut, QByteArray *stdErr,
+ bool showTimeOutMessageBox)
{
if (syncDebug)
qDebug() << ">readDataFromProcess" << timeOutMS;
if (stdErr)
stdErr->append(newStdErr);
}
+ // Prompt user, pretend we have data if says 'No'.
+ const bool hang = !hasData && !finished;
+ if (hang && showTimeOutMessageBox) {
+ if (!askToKill())
+ hasData = true;
+ }
} while (hasData && !finished);
if (syncDebug)
qDebug() << "<readDataFromProcess" << finished;
#include <QtCore/QObject>
#include <QtCore/QProcess>
#include <QtCore/QStringList>
+#include <QtCore/QSharedPointer>
QT_BEGIN_NAMESPACE
class QTextCodec;
SynchronousProcessResponse();
void clear();
+ // Helper to format an exit message.
+ QString exitMessage(const QString &binary, int timeoutMS) const;
+
Result result;
int exitCode;
QString stdOut;
* There is a timeout handling that takes effect after the last data have been
* read from stdout/stdin (as opposed to waitForFinished(), which measures time
* since it was invoked). It is thus also suitable for slow processes that continously
- * output data (like version system operations). */
+ * output data (like version system operations).
+ *
+ * The property timeOutMessageBoxEnabled influences whether a message box is
+ * shown asking the user if they want to kill the process on timeout (default: false). */
class QTCREATOR_UTILS_EXPORT SynchronousProcess : public QObject
{
Q_OBJECT
public:
+ enum Flags {
+ // Unix: Do not give the child process a terminal for input prompting.
+ UnixTerminalDisabled = 0x1
+ };
+
SynchronousProcess();
virtual ~SynchronousProcess();
bool stdErrBufferedSignalsEnabled() const;
void setStdErrBufferedSignalsEnabled(bool);
+ bool timeOutMessageBoxEnabled() const;
+ void setTimeOutMessageBoxEnabled(bool);
+
QStringList environment() const;
void setEnvironment(const QStringList &);
void setWorkingDirectory(const QString &workingDirectory);
QString workingDirectory() const;
+ unsigned flags() const;
+ void setFlags(unsigned);
+
SynchronousProcessResponse run(const QString &binary, const QStringList &args);
+ // Create a (derived) processes with flags applied.
+ static QSharedPointer<QProcess> createProcess(unsigned flags);
+
// Static helper for running a process synchronously in the foreground with timeout
// detection similar SynchronousProcess' handling (taking effect after no more output
// occurs on stderr/stdout as opposed to waitForFinished()). Returns false if a timeout
// occurs. Checking of the process' exit state/code still has to be done.
static bool readDataFromProcess(QProcess &p, int timeOutMS,
- QByteArray *stdOut = 0, QByteArray *stdErr = 0);
+ QByteArray *stdOut = 0, QByteArray *stdErr = 0,
+ bool timeOutMessageBox = false);
// Stop a process by first calling terminate() (allowing for signal handling) and
// then kill().
static bool stopProcess(QProcess &p);
**************************************************************************/
#include "uncommentselection.h"
+#include <QtCore/QtGlobal>
#include <QtGui/QPlainTextEdit>
#include <QtGui/QTextCursor>
#include <QtGui/QTextBlock>
#include <QtGui/QTextDocument>
-void Utils::unCommentSelection(QPlainTextEdit *edit)
+using namespace Utils;
+
+CommentDefinition::CommentDefinition() :
+ m_afterWhiteSpaces(false),
+ m_singleLine(QLatin1String("//")),
+ m_multiLineStart(QLatin1String("/*")),
+ m_multiLineEnd(QLatin1String("*/"))
+{}
+
+CommentDefinition &CommentDefinition::setAfterWhiteSpaces(const bool afterWhiteSpaces)
+{
+ m_afterWhiteSpaces = afterWhiteSpaces;
+ return *this;
+}
+
+CommentDefinition &CommentDefinition::setSingleLine(const QString &singleLine)
+{
+ m_singleLine = singleLine;
+ return *this;
+}
+
+CommentDefinition &CommentDefinition::setMultiLineStart(const QString &multiLineStart)
+{
+ m_multiLineStart = multiLineStart;
+ return *this;
+}
+
+CommentDefinition &CommentDefinition::setMultiLineEnd(const QString &multiLineEnd)
{
+ m_multiLineEnd = multiLineEnd;
+ return *this;
+}
+
+bool CommentDefinition::isAfterWhiteSpaces() const
+{ return m_afterWhiteSpaces; }
+
+const QString &CommentDefinition::singleLine() const
+{ return m_singleLine; }
+
+const QString &CommentDefinition::multiLineStart() const
+{ return m_multiLineStart; }
+
+const QString &CommentDefinition::multiLineEnd() const
+{ return m_multiLineEnd; }
+
+bool CommentDefinition::hasSingleLineStyle() const
+{ return !m_singleLine.isEmpty(); }
+
+bool CommentDefinition::hasMultiLineStyle() const
+{ return !m_multiLineStart.isEmpty() && !m_multiLineEnd.isEmpty(); }
+
+void CommentDefinition::clearCommentStyles()
+{
+ m_singleLine.clear();
+ m_multiLineStart.clear();
+ m_multiLineEnd.clear();
+}
+
+namespace {
+
+bool isComment(const QString &text,
+ int index,
+ const CommentDefinition &definition,
+ const QString & (CommentDefinition::* comment) () const)
+{
+ const QString &commentType = ((definition).*(comment))();
+ const int length = commentType.length();
+
+ Q_ASSERT(text.length() - index >= length);
+
+ int i = 0;
+ while (i < length) {
+ if (text.at(index + i) != commentType.at(i))
+ return false;
+ ++i;
+ }
+ return true;
+}
+
+} // namespace anynomous
+
+
+void Utils::unCommentSelection(QPlainTextEdit *edit, const CommentDefinition &definition)
+{
+ if (!definition.hasSingleLineStyle() && !definition.hasMultiLineStyle())
+ return;
+
QTextCursor cursor = edit->textCursor();
QTextDocument *doc = cursor.document();
cursor.beginEditBlock();
endBlock = endBlock.previous();
}
- bool doCStyleUncomment = false;
- bool doCStyleComment = false;
- bool doCppStyleUncomment = false;
+ bool doMultiLineStyleUncomment = false;
+ bool doMultiLineStyleComment = false;
+ bool doSingleLineStyleUncomment = false;
bool hasSelection = cursor.hasSelection();
- if (hasSelection) {
+ if (hasSelection && definition.hasMultiLineStyle()) {
+
QString startText = startBlock.text();
int startPos = start - startBlock.position();
+ const int multiLineStartLength = definition.multiLineStart().length();
bool hasLeadingCharacters = !startText.left(startPos).trimmed().isEmpty();
- if ((startPos >= 2
- && startText.at(startPos-2) == QLatin1Char('/')
- && startText.at(startPos-1) == QLatin1Char('*'))) {
- startPos -= 2;
- start -= 2;
- }
- bool hasSelStart = (startPos < startText.length() - 1
- && startText.at(startPos) == QLatin1Char('/')
- && startText.at(startPos+1) == QLatin1Char('*'));
+ if (startPos >= multiLineStartLength
+ && isComment(startText,
+ startPos - multiLineStartLength,
+ definition,
+ &CommentDefinition::multiLineStart)) {
+ startPos -= multiLineStartLength;
+ start -= multiLineStartLength;
+ }
+ bool hasSelStart = (startPos <= startText.length() - multiLineStartLength
+ && isComment(startText,
+ startPos,
+ definition,
+ &CommentDefinition::multiLineStart));
QString endText = endBlock.text();
int endPos = end - endBlock.position();
- bool hasTrailingCharacters = !endText.left(endPos).remove(QLatin1String("//")).trimmed().isEmpty()
- && !endText.mid(endPos).trimmed().isEmpty();
- if ((endPos <= endText.length() - 2
- && endText.at(endPos) == QLatin1Char('*')
- && endText.at(endPos+1) == QLatin1Char('/'))) {
- endPos += 2;
- end += 2;
+ const int multiLineEndLength = definition.multiLineEnd().length();
+ bool hasTrailingCharacters =
+ !endText.left(endPos).remove(definition.singleLine()).trimmed().isEmpty()
+ && !endText.mid(endPos).trimmed().isEmpty();
+
+ if (endPos <= endText.length() - multiLineEndLength
+ && isComment(endText, endPos, definition, &CommentDefinition::multiLineEnd)) {
+ endPos += multiLineEndLength;
+ end += multiLineEndLength;
}
- bool hasSelEnd = (endPos >= 2
- && endText.at(endPos-2) == QLatin1Char('*')
- && endText.at(endPos-1) == QLatin1Char('/'));
+ bool hasSelEnd = (endPos >= multiLineEndLength
+ && isComment(endText,
+ endPos - multiLineEndLength,
+ definition,
+ &CommentDefinition::multiLineEnd));
+
+ doMultiLineStyleUncomment = hasSelStart && hasSelEnd;
+ doMultiLineStyleComment = !doMultiLineStyleUncomment
+ && (hasLeadingCharacters
+ || hasTrailingCharacters
+ || !definition.hasSingleLineStyle());
+ } else if (!hasSelection && !definition.hasSingleLineStyle()) {
- doCStyleUncomment = hasSelStart && hasSelEnd;
- doCStyleComment = !doCStyleUncomment && (hasLeadingCharacters || hasTrailingCharacters);
+ QString text = startBlock.text().trimmed();
+ doMultiLineStyleUncomment = text.startsWith(definition.multiLineStart())
+ && text.endsWith(definition.multiLineEnd());
+ doMultiLineStyleComment = !doMultiLineStyleUncomment && !text.isEmpty();
+
+ start = startBlock.position();
+ end = endBlock.position() + endBlock.length() - 1;
+
+ if (doMultiLineStyleUncomment) {
+ int offset = 0;
+ text = startBlock.text();
+ const int length = text.length();
+ while (offset < length && text.at(offset).isSpace())
+ ++offset;
+ start += offset;
+ }
}
- if (doCStyleUncomment) {
+ if (doMultiLineStyleUncomment) {
cursor.setPosition(end);
- cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, 2);
+ cursor.movePosition(QTextCursor::PreviousCharacter,
+ QTextCursor::KeepAnchor,
+ definition.multiLineEnd().length());
cursor.removeSelectedText();
cursor.setPosition(start);
- cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2);
+ cursor.movePosition(QTextCursor::NextCharacter,
+ QTextCursor::KeepAnchor,
+ definition.multiLineStart().length());
cursor.removeSelectedText();
- } else if (doCStyleComment) {
+ } else if (doMultiLineStyleComment) {
cursor.setPosition(end);
- cursor.insertText(QLatin1String("*/"));
+ cursor.insertText(definition.multiLineEnd());
cursor.setPosition(start);
- cursor.insertText(QLatin1String("/*"));
+ cursor.insertText(definition.multiLineStart());
} else {
endBlock = endBlock.next();
- doCppStyleUncomment = true;
+ doSingleLineStyleUncomment = true;
for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
QString text = block.text().trimmed();
- if (!text.isEmpty() && !text.startsWith(QLatin1String("//"))) {
- doCppStyleUncomment = false;
+ if (!text.isEmpty() && !text.startsWith(definition.singleLine())) {
+ doSingleLineStyleUncomment = false;
break;
}
}
+
+ const int singleLineLength = definition.singleLine().length();
for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
- if (doCppStyleUncomment) {
+ if (doSingleLineStyleUncomment) {
QString text = block.text();
int i = 0;
- while (i < text.size() - 1) {
- if (text.at(i) == QLatin1Char('/')
- && text.at(i + 1) == QLatin1Char('/')) {
+ while (i <= text.size() - singleLineLength) {
+ if (isComment(text, i, definition, &CommentDefinition::singleLine)) {
cursor.setPosition(block.position() + i);
- cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2);
+ cursor.movePosition(QTextCursor::NextCharacter,
+ QTextCursor::KeepAnchor,
+ singleLineLength);
cursor.removeSelectedText();
break;
}
QString text = block.text();
foreach(QChar c, text) {
if (!c.isSpace()) {
- cursor.setPosition(block.position());
- cursor.insertText(QLatin1String("//"));
+ if (definition.isAfterWhiteSpaces())
+ cursor.setPosition(block.position() + text.indexOf(c));
+ else
+ cursor.setPosition(block.position());
+ cursor.insertText(definition.singleLine());
break;
}
}
}
// adjust selection when commenting out
- if (hasSelection && !doCStyleUncomment && !doCppStyleUncomment) {
+ if (hasSelection && !doMultiLineStyleUncomment && !doSingleLineStyleUncomment) {
cursor = edit->textCursor();
- if (!doCStyleComment)
- start = startBlock.position(); // move the double slashes into the selection
+ if (!doMultiLineStyleComment)
+ start = startBlock.position(); // move the comment into the selection
int lastSelPos = anchorIsStart ? cursor.position() : cursor.anchor();
if (anchorIsStart) {
cursor.setPosition(start);
cursor.endEditBlock();
}
-
#include "utils_global.h"
+#include <QtCore/QString>
+
QT_BEGIN_NAMESPACE
class QPlainTextEdit;
QT_END_NAMESPACE
namespace Utils {
-QTCREATOR_UTILS_EXPORT void unCommentSelection(QPlainTextEdit *edit);
+class QTCREATOR_UTILS_EXPORT CommentDefinition
+{
+public:
+ CommentDefinition();
+
+ CommentDefinition &setAfterWhiteSpaces(const bool);
+ CommentDefinition &setSingleLine(const QString &singleLine);
+ CommentDefinition &setMultiLineStart(const QString &multiLineStart);
+ CommentDefinition &setMultiLineEnd(const QString &multiLineEnd);
+
+ bool isAfterWhiteSpaces() const;
+ const QString &singleLine() const;
+ const QString &multiLineStart() const;
+ const QString &multiLineEnd() const;
+
+ bool hasSingleLineStyle() const;
+ bool hasMultiLineStyle() const;
+
+ void clearCommentStyles();
+
+private:
+ bool m_afterWhiteSpaces;
+ QString m_singleLine;
+ QString m_multiLineStart;
+ QString m_multiLineEnd;
+};
+
+QTCREATOR_UTILS_EXPORT
+void unCommentSelection(QPlainTextEdit *edit,
+ const CommentDefinition &definiton = CommentDefinition());
} // end of namespace Utils
-<plugin name="BinEditor" version="2.0.80" compatVersion="2.0.80">
+<plugin name="BinEditor" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Binary editor component.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
- <dependency name="TextEditor" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
</dependencyList>
</plugin>
m_baseAddr = static_cast<quint64>(range/2) > startAddr
? 0 : startAddr - range/2;
m_baseAddr = (m_baseAddr / blockSize) * blockSize;
- m_size = m_baseAddr != 0 && static_cast<quint64>(range) >= -m_baseAddr
- ? -m_baseAddr : range;
+ const quint64 maxRange = Q_UINT64_C(0xffffffffffffffff) - m_baseAddr + 1;
+ m_size = m_baseAddr != 0 && static_cast<quint64>(range) >= maxRange
+ ? maxRange : range;
m_addressBytes = (m_baseAddr + m_size < quint64(1) << 32
&& m_baseAddr + m_size >= m_baseAddr) ? 4 : 8;
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_size)
+ int dataPos = (topLine + line) * 16 + column;
+ if (dataPos < 0 || dataPos >= m_size)
break;
- QChar qc(QLatin1Char(dataAt(pos)));
+ QChar qc(QLatin1Char(dataAt(dataPos)));
if (!qc.isPrint())
qc = 0xB7;
x -= fontMetrics().width(qc);
}
}
+ void rename(const QString &newName) {
+ m_fileName = newName;
+ m_editor->editorInterface()->setDisplayName(QFileInfo(fileName()).fileName());
+ emit changed();
+ }
+
bool open(const QString &fileName) {
QFile file(fileName);
if (file.open(QIODevice::ReadOnly)) {
m_toolBar->addWidget(w);
connect(m_editor, SIGNAL(cursorPositionChanged(int)), this, SLOT(updateCursorPosition(int)));
+ connect(m_file, SIGNAL(changed()), this, SIGNAL(changed()));
}
~BinEditorInterface() {
delete m_editor;
layout->setMargin(0);
m_imageView->setLayout(layout);
layout->addWidget(m_label, 0, 0, 1, 1);
+
+ connect(m_file, SIGNAL(changed()),
+ this, SIGNAL(changed()));
}
ImageViewer::~ImageViewer()
explicit ImageViewerFile(ImageViewer *parent = 0);
bool save(const QString &fileName = QString()) { Q_UNUSED(fileName); return false; }
+ void rename(const QString &newName) { m_fileName = newName; }
QString fileName() const { return m_fileName; }
QString defaultPath() const { return QString(); }
-<plugin name="Bookmarks" version="2.0.80" compatVersion="2.0.80">
+<plugin name="Bookmarks" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Bookmarks in text editors.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
- <dependency name="Core" version="2.0.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
+ <dependency name="Core" version="2.1.80"/>
</dependencyList>
</plugin>
BookmarksPlugin *BookmarksPlugin::m_instance = 0;
BookmarksPlugin::BookmarksPlugin()
- : m_bookmarkManager(0)
+ : m_bookmarkManager(0),
+ m_bookmarkMarginActionLineNumber(0)
{
m_instance = this;
}
-<plugin name="CMakeProjectManager" version="2.0.80" compatVersion="2.0.80">
+<plugin name="CMakeProjectManager" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>CMake support</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
- <dependency name="CppTools" version="2.0.80"/>
- <dependency name="CppEditor" version="2.0.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
+ <dependency name="CppTools" version="2.1.80"/>
+ <dependency name="CppEditor" version="2.1.80"/>
</dependencyList>
</plugin>
return false;
}
+void CMakeFile::rename(const QString &newName)
+{
+ Q_ASSERT(false);
+ Q_UNUSED(newName);
+ // Can't happen....
+}
+
Core::IFile::ReloadBehavior CMakeFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
{
Q_UNUSED(state)
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
void reload(ReloadFlag flag, ChangeType type);
+ void rename(const QString &newName);
+
private:
CMakeProject *m_project;
QString m_fileName;
return true;
}
-QList<ProjectExplorer::ProjectNode::ProjectAction> CMakeProjectNode::supportedActions() const
+QList<ProjectExplorer::ProjectNode::ProjectAction> CMakeProjectNode::supportedActions(Node *node) const
{
+ Q_UNUSED(node);
return QList<ProjectAction>();
}
public:
CMakeProjectNode(const QString &fileName);
virtual bool hasBuildTargets() const;
- virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions() const;
+ virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions(Node *node) const;
virtual bool addSubProjects(const QStringList &proFilePaths);
virtual bool removeSubProjects(const QStringList &proFilePaths);
virtual bool addFiles(const ProjectExplorer::FileType fileType,
-<plugin name="Core" version="2.0.80" compatVersion="2.0.80">
+<plugin name="Core" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
namespace Constants {
#define IDE_VERSION_MAJOR 2
-#define IDE_VERSION_MINOR 0
+#define IDE_VERSION_MINOR 1
#define IDE_VERSION_RELEASE 80
#define STRINGIFY_INTERNAL(x) #x
emit editorAboutToClose(editor);
- EditorView *view = m_d->m_splitter->findView(editor)->view();
- removeEditor(editor);
- view->removeEditor(editor);
+ if(m_d->m_splitter->findView(editor)) {
+ EditorView *view = m_d->m_splitter->findView(editor)->view();
+ removeEditor(editor);
+ view->removeEditor(editor);
- IEditor *newCurrent = view->currentEditor();
- if (!newCurrent)
- newCurrent = pickUnusedEditor();
- if (newCurrent) {
- activateEditor(view, newCurrent, NoActivate);
- } else {
- QModelIndex idx = m_d->m_editorModel->firstRestoredEditor();
- if (idx.isValid())
- activateEditor(idx, view, NoActivate);
+ IEditor *newCurrent = view->currentEditor();
+ if (!newCurrent)
+ newCurrent = pickUnusedEditor();
+ if (newCurrent) {
+ activateEditor(view, newCurrent, NoActivate);
+ } else {
+ QModelIndex idx = m_d->m_editorModel->firstRestoredEditor();
+ if (idx.isValid())
+ activateEditor(idx, view, NoActivate);
+ }
}
emit editorsClosed(QList<IEditor*>() << editor);
{
m_statusHLine->setFrameStyle(QFrame::HLine);
- m_statusWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);
- m_statusWidget->setLineWidth(1);
+ m_statusWidget->setFrameStyle(QFrame::NoFrame);
+ m_statusWidget->setLineWidth(0);
//m_statusWidget->setForegroundRole(QPalette::ToolTipText);
//m_statusWidget->setBackgroundRole(QPalette::ToolTipBase);
m_statusWidget->setAutoFillBackground(true);
-
QHBoxLayout *hbox = new QHBoxLayout(m_statusWidget);
- hbox->setMargin(2);
- m_statusWidgetLabel = new QLabel("Placeholder");
+ hbox->setContentsMargins(1, 0, 1, 1);
+ m_statusWidgetLabel = new QLabel;
m_statusWidgetLabel->setForegroundRole(QPalette::ToolTipText);
+ m_statusWidgetLabel->setContentsMargins(3, 0, 3, 0);
hbox->addWidget(m_statusWidgetLabel);
hbox->addStretch(1);
m_statusWidgetButton = new QToolButton;
- m_statusWidgetButton->setText(tr("Placeholder"));
+ m_statusWidgetButton->setContentsMargins(0, 0, 0, 0);
+ //m_statusWidgetButton->setIcon(QIcon(":/core/images/clear.png"));
hbox->addWidget(m_statusWidgetButton);
m_statusHLine->setVisible(false);
m_statusWidgetId = id;
m_statusWidgetLabel->setText(infoText);
m_statusWidgetButton->setText(buttonText);
+ m_statusWidgetButton->setToolTip(buttonText);
m_statusWidgetButton->disconnect();
if (object && member)
connect(m_statusWidgetButton, SIGNAL(clicked()), object, member);
QString m_lastVisitedDirectory;
QString m_projectsDirectory;
bool m_useProjectsDirectory;
+ // When we are callling into a IFile
+ // we don't want to receive a changed()
+ // signal
+ // That makes the code easier
+ IFile *m_blockedIFile;
};
FileManagerPrivate::FileManagerPrivate(QObject *q, QMainWindow *mw) :
m_blockActivated(false),
m_lastVisitedDirectory(QDir::currentPath()),
#ifdef Q_OS_MAC // Creator is in bizarre places when launched via finder.
- m_useProjectsDirectory(true)
+ m_useProjectsDirectory(true),
#else
- m_useProjectsDirectory(false)
+ m_useProjectsDirectory(false),
#endif
+ m_blockedIFile(0)
{
}
d->m_states[fixedname].lastUpdatedState.insert(file, item);
}
+/// Dumps the state of the file manager's map
+/// For debugging purposes
+void FileManager::dump()
+{
+ QMap<QString, Internal::FileState>::const_iterator it, end;
+ it = d->m_states.constBegin();
+ end = d->m_states.constEnd();
+ for (; it != end; ++it) {
+ qDebug()<<" ";
+ qDebug() << it.key();
+ qDebug() << it.value().expected.modified;
+
+ QMap<IFile *, Internal::FileStateItem>::const_iterator jt, jend;
+ jt = it.value().lastUpdatedState.constBegin();
+ jend = it.value().lastUpdatedState.constEnd();
+ for (; jt != jend; ++jt) {
+ qDebug() << jt.key() << jt.value().modified;
+ }
+ }
+}
+
+void FileManager::renamedFile(const QString &from, QString &to)
+{
+ QString fixedFrom = fixFileName(from);
+ QString fixedTo = fixFileName(to);
+ if (d->m_states.contains(fixedFrom)) {
+ QTC_ASSERT(!d->m_states.contains(to), return);
+ d->m_states.insert(fixedTo, d->m_states.value(fixedFrom));
+ d->m_states.remove(fixedFrom);
+ QFileInfo fi(to);
+ d->m_states[fixedTo].expected.modified = fi.lastModified();
+ d->m_states[fixedTo].expected.permissions = fi.permissions();
+
+ d->m_fileWatcher->removePath(fixedFrom);
+ d->m_fileWatcher->addPath(fixedTo);
+
+ QMap<IFile *, Internal::FileStateItem>::iterator it, end;
+ it = d->m_states[fixedTo].lastUpdatedState.begin();
+ end = d->m_states[fixedTo].lastUpdatedState.end();
+
+ for ( ; it != end; ++it) {
+ d->m_blockedIFile = it.key();
+ it.key()->rename(to);
+ d->m_blockedIFile = it.key();
+ it.value().modified = fi.lastModified();
+ }
+ }
+}
+
///
/// Does not use file->fileName, as such is save to use
/// with renamed files and deleted files
void FileManager::checkForNewFileName()
{
IFile *file = qobject_cast<IFile *>(sender());
+ // We modified the IFile
+ // Trust the other code to also update the m_states map
+ if (file == d->m_blockedIFile)
+ return;
QTC_ASSERT(file, return);
const QString &fileName = fixFileName(file->fileName());
end = lastUpdated.constEnd();
for ( ; it != end; ++it) {
IFile *file = it.key();
+ d->m_blockedIFile = file;
// Compare
if (it.value().modified == fi.lastModified()
&& it.value().permissions == fi.permissions()) {
}
updateFileInfo(file);
+ d->m_blockedIFile = 0;
}
}
bool isFileManaged(const QString &fileName) const;
QList<IFile *> modifiedFiles() const;
+ void renamedFile(const QString &from, QString &to);
+
void blockFileChange(IFile *file);
void unblockFileChange(IFile *file);
QStringList recentFiles() const;
void saveRecentFiles();
+
// current file
void setCurrentFile(const QString &filePath);
QString currentFile() const;
void syncWithEditor(Core::IContext *context);
private:
+ void dump();
void addFileInfo(IFile *file);
void removeFileInfo(IFile *file);
void removeFileInfo(const QString &fileName, IFile *file);
virtual ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const = 0;
virtual void reload(ReloadFlag flag, ChangeType type) = 0;
+ virtual void rename(const QString &newName) = 0;
virtual void checkPermissions() {}
Q_OBJECT
public:
enum Operation {
- AddOperation, DeleteOperation, OpenOperation,
+ AddOperation, DeleteOperation, OpenOperation, MoveOperation,
CreateRepositoryOperation,
SnapshotOperations,
AnnotateOperation
/*!
* Returns whether files in this directory should be managed with this
* version control.
+ * If \a topLevel is non-null, it should return the topmost directory,
+ * for which this IVersionControl should be used. The VCSManager assumes
+ * that all files in the returned directory are managed by the same IVersionControl.
*/
- virtual bool managesDirectory(const QString &filename) const = 0;
- /*!
- * This function should return the topmost directory, for which this
- * IVersionControl should be used. The VCSManager assumes that all files in
- * the returned directory are managed by the same IVersionControl.
- *
- * Note that this is used as an optimization, so that the VCSManager
- * doesn't need to call managesDirectory(..) for each directory.
- *
- * This function is called after finding out that the directory is managed
- * by a specific version control.
- */
- virtual QString findTopLevelForDirectory(const QString &directory) const = 0;
+ virtual bool managesDirectory(const QString &filename, QString *topLevel = 0) const = 0;
/*!
* Called to query whether a VCS supports the respective operations.
virtual bool vcsDelete(const QString &filename) = 0;
/*!
+ * Called to rename a file, should do the actual on disk renaming
+ * (e.g. git mv, svn move, p4 move)
+ */
+ virtual bool vcsMove(const QString &from, const QString &to) = 0;
+
+ /*!
* Called to initialize the version control system in a directory.
*/
virtual bool vcsCreateRepository(const QString &directory) = 0;
void MainWindow::setFocusToEditor()
{
- QWidget *focusWidget = qApp->focusWidget();
- if (!EditorManager::instance()->isVisible())
- {
- m_coreImpl->modeManager()->activateMode(QLatin1String(Constants::MODE_EDIT));
- }
+ bool focusWasMovedToEditor = false;
- if (IEditor *editor = m_editorManager->currentEditor())
+ // give focus to the editor if we have one
+ if (IEditor *editor = m_editorManager->currentEditor()) {
+ if (qApp->focusWidget() != editor->widget()) {
editor->widget()->setFocus();
-
- bool focusWasAlreadyInEditor = (focusWidget && focusWidget == qApp->focusWidget());
- if (!focusWasAlreadyInEditor) {
- if (OutputPanePlaceHolder::getCurrent() &&
- OutputPanePlaceHolder::getCurrent()->isVisible())
- OutputPanePlaceHolder::getCurrent()->unmaximize();
- } else {
- bool stuffVisible =
- (FindToolBarPlaceHolder::getCurrent() &&
- FindToolBarPlaceHolder::getCurrent()->isVisible())
- || (OutputPanePlaceHolder::getCurrent() &&
- OutputPanePlaceHolder::getCurrent()->isVisible())
- || (RightPanePlaceHolder::current() &&
- RightPanePlaceHolder::current()->isVisible());
- if (stuffVisible) {
- if (FindToolBarPlaceHolder::getCurrent())
- FindToolBarPlaceHolder::getCurrent()->hide();
- OutputPaneManager::instance()->slotHide();
- RightPaneWidget::instance()->setShown(false);
- } else {
- m_coreImpl->modeManager()->activateMode(QLatin1String(Constants::MODE_EDIT));
+ focusWasMovedToEditor = true;
}
}
+
+ // check for some maximized pane which we want to unmaximize
+ if (OutputPanePlaceHolder::getCurrent()
+ && OutputPanePlaceHolder::getCurrent()->isVisible()
+ && OutputPanePlaceHolder::getCurrent()->isMaximized()) {
+ OutputPanePlaceHolder::getCurrent()->unmaximize();
+ return;
+ }
+
+ if (focusWasMovedToEditor)
+ return;
+
+
+ // check for some visible bar which we want to hide
+ bool stuffVisible =
+ (FindToolBarPlaceHolder::getCurrent() &&
+ FindToolBarPlaceHolder::getCurrent()->isVisible())
+ || (OutputPanePlaceHolder::getCurrent() &&
+ OutputPanePlaceHolder::getCurrent()->isVisible())
+ || (RightPanePlaceHolder::current() &&
+ RightPanePlaceHolder::current()->isVisible());
+ if (stuffVisible) {
+ if (FindToolBarPlaceHolder::getCurrent())
+ FindToolBarPlaceHolder::getCurrent()->hide();
+ OutputPaneManager::instance()->slotHide();
+ RightPaneWidget::instance()->setShown(false);
+ return;
+ }
+
+ // switch to edit mode if necessary
+ m_coreImpl->modeManager()->activateMode(QLatin1String(Constants::MODE_EDIT));
+
}
QStringList MainWindow::showNewItemDialog(const QString &title,
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
+#include <QtCore/QMutex>
#include <QtCore/QThread>
+#include <QtCore/QWaitCondition>
#include <ne7ssh.h>
quit();
}
- bool start(bool shell)
+ bool start(bool shell, void (*callbackFunc)(void *), void *callbackArg)
{
Q_ASSERT(m_channel == -1);
try {
const QString *authString;
int (ne7ssh::*connFunc)(const char *, int, const char *,
- const char *, bool, int);
+ const char *, bool, int, void (*)(void *), void *);
if (m_server.authType == SshServerInfo::AuthByPwd) {
authString = &m_server.pwd;
connFunc = &ne7ssh::connectWithPassword;
connFunc = &ne7ssh::connectWithKey;
}
m_channel = (ssh.data()->*connFunc)(m_server.host.toLatin1(),
- m_server.port, m_server.uname.toAscii(),
- authString->toLatin1(), shell, m_server.timeout);
+ m_server.port, m_server.uname.toAscii(), authString->toLatin1(),
+ shell, m_server.timeout, callbackFunc, callbackArg);
if (m_channel == -1) {
setError(tr("Could not connect to host."), false);
return false;
}
} catch (const std::exception &e) {
- // Should in theory not be necessary, but Net7 leaks Botan exceptions.
+ // Should in theory not be necessary, but Net7 leaks Botan exceptions.
setError(tr("Error in cryptography backend: %1")
.arg(QLatin1String(e.what())), false);
return false;
}
}
+ bool isConnected() const { return channel() != -1; }
bool hasError() const { return !m_error.isEmpty(); }
QString error() const { return m_error; }
int channel() const { return m_channel; }
int m_channel;
};
-
char *alloc(size_t n)
{
return new char[n];
GenericSshConnection conn;
ConnectionOutputReader *outputReader;
+ QByteArray remoteOutput;
+ QMutex mutex;
+ QWaitCondition waitCond;
};
struct NonInteractiveSshConnectionPrivate
{
public:
ConnectionOutputReader(InteractiveSshConnection *parent)
- : QThread(parent), m_conn(parent), m_stopRequested(false)
+ : QThread(parent), m_conn(parent), m_stopRequested(false),
+ m_dataAvailable(false)
{}
~ConnectionOutputReader()
wait();
}
- // TODO: Use a wakeup mechanism here as soon as we no longer poll for output
- // from Net7.
void stop()
{
+ m_mutex.lock();
m_stopRequested = true;
+ m_waitCond.wakeOne();
+ m_mutex.unlock();
+ }
+
+ void dataAvailable()
+ {
+ m_mutex.lock();
+ m_dataAvailable = true;
+ m_waitCond.wakeOne();
+ m_mutex.unlock();
}
private:
virtual void run()
{
- while (!m_stopRequested) {
+ while (true) {
+ m_mutex.lock();
+ if (m_stopRequested) {
+ m_mutex.unlock();
+ return;
+ }
const int channel = m_conn->d->conn.channel();
- if (channel != -1) {
- QScopedPointer<char, QScopedPointerArrayDeleter<char> >
+ if (!m_dataAvailable || channel == -1)
+ m_waitCond.wait(&m_mutex);
+ m_dataAvailable = false;
+ m_mutex.unlock();
+ QScopedPointer<char, QScopedPointerArrayDeleter<char> >
output(m_conn->d->conn.ssh->readAndReset(channel, alloc));
- if (output)
- emit m_conn->remoteOutput(QByteArray(output.data()));
+ if (output) {
+ m_conn->d->mutex.lock();
+ m_conn->d->remoteOutput += output.data();
+ emit m_conn->remoteOutputAvailable();
+ m_conn->d->mutex.unlock();
}
- usleep(100000); // TODO: Hack Net7 to enable wait() functionality.
}
}
InteractiveSshConnection *m_conn;
bool m_stopRequested;
+ bool m_dataAvailable;
+ QMutex m_mutex;
+ QWaitCondition m_waitCond;
};
} // namespace Internal
+namespace {
+
+void wakeupReader(void *opaqueReader)
+{
+ static_cast<Internal::ConnectionOutputReader*>(opaqueReader)->dataAvailable();
+}
+
+} // Anonymous namespace
+
+
InteractiveSshConnection::InteractiveSshConnection(const SshServerInfo &server)
: d(new Internal::InteractiveSshConnectionPrivate(server))
{
bool InteractiveSshConnection::start()
{
- if (!d->conn.start(true))
+ if (isConnected())
+ return true;
+
+ if (!d->conn.start(true, wakeupReader, d->outputReader))
return false;
d->outputReader->start();
void InteractiveSshConnection::quit()
{
+ d->mutex.lock();
+ d->waitCond.wakeOne();
+ d->mutex.unlock();
d->outputReader->stop();
d->conn.quit();
}
+QByteArray InteractiveSshConnection::waitForRemoteOutput(int msecs)
+{
+ d->mutex.lock();
+ if (d->remoteOutput.isEmpty())
+ d->waitCond.wait(&d->mutex, msecs == -1 ? ULONG_MAX : msecs);
+ const QByteArray remoteOutput = d->remoteOutput;
+ d->remoteOutput.clear();
+ d->mutex.unlock();
+ return remoteOutput;
+}
+
+
InteractiveSshConnection::Ptr InteractiveSshConnection::create(const SshServerInfo &server)
{
return Ptr(new InteractiveSshConnection(server));
}
+bool InteractiveSshConnection::isConnected() const
+{
+ return d->conn.isConnected();
+}
+
bool InteractiveSshConnection::hasError() const
{
return d->conn.hasError();
bool SftpConnection::start()
{
- if (!d->conn.start(false))
+ if (isConnected())
+ return true;
+ if (!d->conn.start(false, 0, 0))
return false;
if (!d->conn.ssh->initSftp(d->sftp, d->conn.channel())
|| !d->sftp.setTimeout(d->conn.server().timeout)) {
d->conn.setError(tr("Error setting up SFTP subsystem"), true);
+ quit();
return false;
}
return true;
d->conn.quit();
}
+bool SftpConnection::isConnected() const
+{
+ return d->conn.isConnected();
+}
+
bool SftpConnection::hasError() const
{
return d->conn.hasError();
bool start();
void quit();
+ bool isConnected() const;
bool sendInput(const QByteArray &input); // Should normally end in newline.
+ QByteArray waitForRemoteOutput(int msecs = -1);
bool hasError() const;
QString error() const;
~InteractiveSshConnection();
signals:
- void remoteOutput(const QByteArray &output);
+ void remoteOutputAvailable();
private:
InteractiveSshConnection(const SshServerInfo &server);
static Ptr create(const SshServerInfo &server);
bool start();
void quit();
+ bool isConnected() const;
bool hasError() const;
QString error() const;
bool upload(const QString &localFilePath, const QByteArray &remoteFilePath);
QString *topLevelDirectory)
{
typedef VersionControlCache::const_iterator VersionControlCacheConstIterator;
+
+ if (debug) {
+ qDebug(">findVersionControlForDirectory %s topLevelPtr %d",
+ qPrintable(directory), (topLevelDirectory != 0));
+ if (debug > 1) {
+ const VersionControlCacheConstIterator cend = m_d->m_cachedMatches.constEnd();
+ for (VersionControlCacheConstIterator it = m_d->m_cachedMatches.constBegin(); it != cend; ++it)
+ qDebug("Cache %s -> '%s'", qPrintable(it.key()), qPrintable(it.value()->displayName()));
+ }
+ }
+ QTC_ASSERT(!directory.isEmpty(), return 0);
+
const VersionControlCacheConstIterator cacheEnd = m_d->m_cachedMatches.constEnd();
if (topLevelDirectory)
if (fullPathIt != cacheEnd) {
if (topLevelDirectory)
*topLevelDirectory = directory;
+ if (debug)
+ qDebug("<findVersionControlForDirectory: full cache match for VCS '%s'", qPrintable(fullPathIt.value()->displayName()));
return fullPathIt.value();
}
- // Split the path, starting from top, try to find the matching repository
- int pos = 0;
+ // Split the path, trying to find the matching repository. We start from the reverse
+ // in order to detected nested repositories correctly (say, a git checkout under SVN).
+ // Note that detection of a nested version control will still fail if the
+ // above-located version control is detected and entered into the cache first.
+ // The nested one can then no longer be found due to the splitting of the paths.
+ int pos = directory.size() - 1;
const QChar slash = QLatin1Char('/');
while (true) {
- const int index = directory.indexOf(slash, pos);
- if (index == -1)
+ const int index = directory.lastIndexOf(slash, pos);
+ if (index <= 0) // Stop at '/' or not found
break;
const QString directoryPart = directory.left(index);
const VersionControlCacheConstIterator it = m_d->m_cachedMatches.constFind(directoryPart);
if (it != cacheEnd) {
if (topLevelDirectory)
*topLevelDirectory = it.key();
+ if (debug)
+ qDebug("<findVersionControlForDirectory: cache match for VCS '%s', topLevel: %s",
+ qPrintable(it.value()->displayName()), qPrintable(it.key()));
return it.value();
}
- pos = index + 1;
+ pos = index - 1;
}
// Nothing: ask the IVersionControls directly, insert the toplevel into the cache.
const VersionControlList versionControls = allVersionControls();
foreach (IVersionControl * versionControl, versionControls) {
- if (versionControl->managesDirectory(directory)) {
- const QString topLevel = versionControl->findTopLevelForDirectory(directory);
+ QString topLevel;
+ if (versionControl->managesDirectory(directory, &topLevel)) {
m_d->m_cachedMatches.insert(topLevel, versionControl);
if (topLevelDirectory)
*topLevelDirectory = topLevel;
+ if (debug)
+ qDebug("<findVersionControlForDirectory: invocation of '%s' matches: %s",
+ qPrintable(versionControl->displayName()), qPrintable(topLevel));
return versionControl;
}
}
+ if (debug)
+ qDebug("<findVersionControlForDirectory: No match for %s", qPrintable(directory));
return 0;
}
-<plugin name="CodePaster" version="2.0.80" compatVersion="2.0.80">
+<plugin name="CodePaster" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Codepaster plugin for pushing/fetching diff from server</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
- <dependency name="Core" version="2.0.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
+ <dependency name="Core" version="2.1.80"/>
</dependencyList>
</plugin>
-<plugin name="CppEditor" version="2.0.80" compatVersion="2.0.80">
+<plugin name="CppEditor" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>C/C++ editor component.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="CppTools" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="CppTools" version="2.1.80"/>
</dependencyList>
</plugin>
#include <TranslationUnit.h>
#include <cplusplus/ExpressionUnderCursor.h>
#include <cplusplus/TypeOfExpression.h>
-#include <cplusplus/LookupContext.h>
#include <cplusplus/Overview.h>
#include <cplusplus/OverviewModel.h>
#include <cplusplus/SimpleLexer.h>
-#include <cplusplus/TokenUnderCursor.h>
#include <cplusplus/MatchingText.h>
#include <cplusplus/BackwardsScanner.h>
#include <cplusplus/FastPreprocessor.h>
-#include <cplusplus/CppBindings.h>
+#include <cplusplus/CheckUndefinedSymbols.h>
+#include <cplusplus/TokenCache.h>
#include <cpptools/cppmodelmanagerinterface.h>
bool findMemberForToken(unsigned tokenIdx, NameAST *ast)
{
+ const Token &tok = tokenAt(tokenIdx);
+ if (tok.generated())
+ return false;
+
unsigned line, column;
getTokenStartPosition(tokenIdx, &line, &column);
for (TemplateArgumentListAST *arg = ast->template_argument_list; arg; arg = arg->next)
accept(arg->value);
+ const Token &tok = tokenAt(ast->identifier_token);
+ if (tok.generated())
+ return false;
+
unsigned line, column;
getTokenStartPosition(ast->firstToken(), &line, &column);
}
};
-class ProcessDeclarators: protected ASTVisitor
-{
- QList<DeclaratorIdAST *> _declarators;
- bool _visitFunctionDeclarator;
-
-public:
- ProcessDeclarators(TranslationUnit *translationUnit)
- : ASTVisitor(translationUnit),
- _visitFunctionDeclarator(true)
- { }
-
- QList<DeclaratorIdAST *> operator()(FunctionDefinitionAST *ast)
- {
- _declarators.clear();
-
- if (ast) {
- if (ast->declarator) {
- _visitFunctionDeclarator = true;
- accept(ast->declarator->postfix_declarator_list);
- }
-
- _visitFunctionDeclarator = false;
- accept(ast->function_body);
- }
-
- return _declarators;
- }
-
-protected:
- using ASTVisitor::visit;
-
- virtual bool visit(FunctionDeclaratorAST *)
- { return _visitFunctionDeclarator; }
-
- virtual bool visit(DeclaratorIdAST *ast)
- {
- _declarators.append(ast);
- return true;
- }
-};
-
class FindFunctionDefinitions: protected SymbolVisitor
{
const Name *_declarationName;
}
};
-} // end of anonymous namespace
-static const QualifiedNameId *qualifiedNameIdForSymbol(Symbol *s, const LookupContext &context)
+struct FindCanonicalSymbol
{
- const Name *symbolName = s->name();
- if (! symbolName)
- return 0; // nothing to do.
+ CPPEditor *editor;
+ QString code;
+ TypeOfExpression typeOfExpression;
+ ExpressionUnderCursor expressionUnderCursor;
+ SemanticInfo info;
- QVector<const Name *> names;
+ FindCanonicalSymbol(CPPEditor *editor, const SemanticInfo &info)
+ : editor(editor), expressionUnderCursor(editor->tokenCache()), info(info)
+ {
+ typeOfExpression.init(info.doc, info.snapshot);
+ }
- for (Scope *scope = s->scope(); scope; scope = scope->enclosingScope()) {
- if (scope->isClassScope() || scope->isNamespaceScope()) {
- if (scope->owner() && scope->owner()->name()) {
- const Name *ownerName = scope->owner()->name();
- if (const QualifiedNameId *q = ownerName->asQualifiedNameId()) {
- for (unsigned i = 0; i < q->nameCount(); ++i) {
- names.prepend(q->nameAt(i));
- }
- } else {
- names.prepend(ownerName);
- }
- }
- }
+ const LookupContext &context() const
+ {
+ return typeOfExpression.context();
}
- if (const QualifiedNameId *q = symbolName->asQualifiedNameId()) {
- for (unsigned i = 0; i < q->nameCount(); ++i) {
- names.append(q->nameAt(i));
+ inline bool isIdentifierChar(const QChar &ch) const
+ {
+ return ch.isLetterOrNumber() || ch == QLatin1Char('_');
+ }
+
+ Symbol *operator()(const QTextCursor &cursor)
+ {
+ if (! info.doc)
+ return 0;
+
+ QTextCursor tc = cursor;
+ int line, col;
+ editor->convertPosition(tc.position(), &line, &col);
+ ++col; // 1-based line and 1-based column
+
+ QTextDocument *document = editor->document();
+
+ int pos = tc.position();
+
+ if (! isIdentifierChar(document->characterAt(pos)))
+ if (! (pos > 0 && isIdentifierChar(document->characterAt(pos - 1))))
+ return 0;
+
+ while (isIdentifierChar(document->characterAt(pos)))
+ ++pos;
+ tc.setPosition(pos);
+
+ code = expressionUnderCursor(tc);
+ Scope *scope = info.doc->scopeAt(line, col);
+
+ const QList<LookupItem> results = typeOfExpression(code, scope, TypeOfExpression::Preprocess);
+ for (int i = results.size() - 1; i != -1; --i) { // ### TODO virtual methods and classes.
+ const LookupItem &r = results.at(i);
+
+ if (r.declaration())
+ return r.declaration();
}
- } else {
- names.append(symbolName);
+
+ return 0;
}
+};
- return context.control()->qualifiedNameId(names.constData(), names.size());
-}
+} // end of anonymous namespace
CPPEditorEditable::CPPEditorEditable(CPPEditor *editor)
: BaseTextEditorEditable(editor)
finishRename();
}
+TokenCache *CPPEditor::tokenCache() const
+{
+ return m_modelManager->tokenCache(editableInterface());
+}
+
+CppTools::CppModelManagerInterface *CPPEditor::modelManager() const
+{
+ return m_modelManager;
+}
+
void CPPEditor::startRename()
{
m_inRenameChanged = false;
updateMethodBoxIndexNow();
}
-CPlusPlus::Symbol *CPPEditor::findCanonicalSymbol(const QTextCursor &cursor,
- Document::Ptr doc,
- const Snapshot &snapshot) const
-{
- if (! doc)
- return 0;
-
- QTextCursor tc = cursor;
- int line, col;
- convertPosition(tc.position(), &line, &col);
- ++col; // 1-based line and 1-based column
-
- int pos = tc.position();
- while (document()->characterAt(pos).isLetterOrNumber() ||
- document()->characterAt(pos) == QLatin1Char('_'))
- ++pos;
- tc.setPosition(pos);
-
- ExpressionUnderCursor expressionUnderCursor;
- const QString code = expressionUnderCursor(tc);
- // qDebug() << "code:" << code;
-
- TypeOfExpression typeOfExpression;
- typeOfExpression.setSnapshot(snapshot);
-
- Symbol *lastVisibleSymbol = doc->findSymbolAt(line, col);
-
- const QList<LookupItem> results = typeOfExpression(code, doc,
- lastVisibleSymbol,
- TypeOfExpression::Preprocess);
-
- NamespaceBindingPtr glo = bind(doc, snapshot);
- Symbol *canonicalSymbol = LookupContext::canonicalSymbol(results, glo.data());
-
- return canonicalSymbol;
-}
-
-const Macro *CPPEditor::findCanonicalMacro(const QTextCursor &cursor,
- Document::Ptr doc) const
+const Macro *CPPEditor::findCanonicalMacro(const QTextCursor &cursor, Document::Ptr doc) const
{
if (! doc)
return 0;
void CPPEditor::findUsages()
{
- if (Symbol *canonicalSymbol = markSymbols()) {
- m_modelManager->findUsages(m_lastSemanticInfo.doc, canonicalSymbol);
- } else if (const Macro *macro = findCanonicalMacro(textCursor(), m_lastSemanticInfo.doc)) {
+ const SemanticInfo info = m_lastSemanticInfo;
+
+ FindCanonicalSymbol cs(this, info);
+ Symbol *canonicalSymbol = cs(textCursor());
+ if (canonicalSymbol) {
+ m_modelManager->findUsages(canonicalSymbol, cs.context());
+ } else if (const Macro *macro = findCanonicalMacro(textCursor(), info.doc)) {
m_modelManager->findMacroUsages(*macro);
}
}
void CPPEditor::renameUsagesNow()
{
- if (Symbol *canonicalSymbol = markSymbols()) {
+ const SemanticInfo info = m_lastSemanticInfo;
+
+ FindCanonicalSymbol cs(this, info);
+ if (Symbol *canonicalSymbol = cs(textCursor())) {
if (canonicalSymbol->identifier() != 0) {
if (showWarningMessage()) {
Core::EditorManager::instance()->showEditorInfoBar(QLatin1String("CppEditor.Rename"),
this, SLOT(hideRenameNotification()));
}
- m_modelManager->renameUsages(m_lastSemanticInfo.doc, canonicalSymbol);
+ m_modelManager->renameUsages(canonicalSymbol, cs.context());
}
}
}
-Symbol *CPPEditor::markSymbols()
+void CPPEditor::markSymbols(Symbol *canonicalSymbol, const SemanticInfo &info)
{
- updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));
+ //updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource()));
abortRename();
QList<QTextEdit::ExtraSelection> selections;
- SemanticInfo info = m_lastSemanticInfo;
-
- Symbol *canonicalSymbol = findCanonicalSymbol(textCursor(), info.doc, info.snapshot);
if (canonicalSymbol) {
TranslationUnit *unit = info.doc->translationUnit();
- const QList<int> references = m_modelManager->references(canonicalSymbol, info.doc, info.snapshot);
+ const QList<int> references = m_modelManager->references(canonicalSymbol, info.context);
foreach (int index, references) {
unsigned line, column;
unit->getTokenPosition(index, &line, &column);
}
setExtraSelections(CodeSemanticsSelection, selections);
- return canonicalSymbol;
}
void CPPEditor::renameSymbolUnderCursor()
semanticRehighlight();
}
-static bool isCompatible(const Name *name, const Name *otherName)
-{
- if (const NameId *nameId = name->asNameId()) {
- if (const TemplateNameId *otherTemplId = otherName->asTemplateNameId())
- return nameId->identifier()->isEqualTo(otherTemplId->identifier());
- } else if (const TemplateNameId *templId = name->asTemplateNameId()) {
- if (const NameId *otherNameId = otherName->asNameId())
- return templId->identifier()->isEqualTo(otherNameId->identifier());
- }
-
- return name->isEqualTo(otherName);
-}
-
-static bool isCompatible(Function *definition, Symbol *declaration,
- const QualifiedNameId *declarationName)
-{
- Function *declTy = declaration->type()->asFunctionType();
- if (! declTy)
- return false;
-
- const Name *definitionName = definition->name();
- if (const QualifiedNameId *q = definitionName->asQualifiedNameId()) {
- if (! isCompatible(q->unqualifiedNameId(), declaration->name()))
- return false;
- else if (q->nameCount() > declarationName->nameCount())
- return false;
- else if (declTy->argumentCount() != definition->argumentCount())
- return false;
- else if (declTy->isConst() != definition->isConst())
- return false;
- else if (declTy->isVolatile() != definition->isVolatile())
- return false;
-
- for (unsigned i = 0; i < definition->argumentCount(); ++i) {
- Symbol *arg = definition->argumentAt(i);
- Symbol *otherArg = declTy->argumentAt(i);
- if (! arg->type().isEqualTo(otherArg->type()))
- return false;
- }
-
- for (unsigned i = 0; i != q->nameCount(); ++i) {
- const Name *n = q->nameAt(q->nameCount() - i - 1);
- const Name *m = declarationName->nameAt(declarationName->nameCount() - i - 1);
- if (! isCompatible(n, m))
- return false;
- }
- return true;
- } else {
- // ### TODO: implement isCompatible for unqualified name ids.
- }
- return false;
-}
-
void CPPEditor::switchDeclarationDefinition()
{
- int line = 0, column = 0;
- convertPosition(position(), &line, &column);
-
- if (!m_modelManager)
+ if (! m_modelManager)
return;
const Snapshot snapshot = m_modelManager->snapshot();
- Document::Ptr doc = snapshot.document(file()->fileName());
- if (!doc)
- return;
- Symbol *lastSymbol = doc->findSymbolAt(line, column);
- if (!lastSymbol || !lastSymbol->scope())
- return;
-
- Function *f = lastSymbol->asFunction();
- if (!f) {
- Scope *fs = lastSymbol->scope();
- if (!fs->isFunctionScope())
- fs = fs->enclosingFunctionScope();
- if (fs)
- f = fs->owner()->asFunction();
- }
+ if (Document::Ptr thisDocument = snapshot.document(file()->fileName())) {
+ int line = 0, column = 0;
+ convertPosition(position(), &line, &column);
- if (f) {
- TypeOfExpression typeOfExpression;
- typeOfExpression.setSnapshot(m_modelManager->snapshot());
- QList<LookupItem> resolvedSymbols = typeOfExpression(QString(), doc, lastSymbol);
- const LookupContext &context = typeOfExpression.lookupContext();
+ Scope *scope = thisDocument->scopeAt(line, column);
+ Symbol *lastVisibleSymbol = thisDocument->lastVisibleSymbolAt(line, column);
- const QualifiedNameId *q = qualifiedNameIdForSymbol(f, context);
- QList<Symbol *> symbols = context.resolve(q);
+ Scope *functionScope = 0;
+ if (scope->isFunctionScope())
+ functionScope = scope;
+ else
+ functionScope = scope->enclosingFunctionScope();
- Symbol *declaration = 0;
- foreach (declaration, symbols) {
- if (isCompatible(f, declaration, q))
- break;
+ if (! functionScope && lastVisibleSymbol) {
+ if (Function *def = lastVisibleSymbol->asFunction())
+ functionScope = def->members();
}
- if (! declaration && ! symbols.isEmpty())
- declaration = symbols.first();
+ if (functionScope) {
+ LookupContext context(thisDocument, snapshot);
+
+ Function *functionDefinition = functionScope->owner()->asFunction();
+ const QList<Symbol *> declarations = context.lookup(functionDefinition->name(), functionDefinition->scope());
+ foreach (Symbol *decl, declarations) {
+ // TODO: check decl.
+ openCppEditorAt(linkToSymbol(decl));
+ break;
+ }
- if (declaration)
- openCppEditorAt(linkToSymbol(declaration));
- } else if (lastSymbol->type()->isFunctionType()) {
- if (Symbol *def = findDefinition(lastSymbol))
- openCppEditorAt(linkToSymbol(def));
+ } else if (lastVisibleSymbol && lastVisibleSymbol->isDeclaration() && lastVisibleSymbol->type()->isFunctionType()) {
+ if (Symbol *def = snapshot.findMatchingDefinition(lastVisibleSymbol))
+ openCppEditorAt(linkToSymbol(def));
+ }
}
}
SimpleLexer tokenize;
tokenize.setQtMocRunEnabled(true);
const QString blockText = cursor.block().text();
- const QList<SimpleToken> tokens = tokenize(blockText, BackwardsScanner::previousBlockState(cursor.block()));
+ const QList<SimpleToken> tokens = tokenize(blockText, TokenCache::previousBlockState(cursor.block()));
bool recognizedQtMethod = false;
}
if (! recognizedQtMethod) {
- static TokenUnderCursor tokenUnderCursor;
-
- QTextBlock block;
- const SimpleToken tk = tokenUnderCursor(tc, &block);
+ const QTextBlock block = tc.block();
+ const SimpleToken tk = tokenCache()->tokenUnderCursor(tc);
beginOfToken = block.position() + tk.begin();
endOfToken = block.position() + tk.end();
}
// Find the last symbol up to the cursor position
- Symbol *lastSymbol = doc->findSymbolAt(line, column);
- if (!lastSymbol)
+ Scope *scope = doc->scopeAt(line, column);
+ if (!scope)
return link;
// Evaluate the type of the expression under the cursor
- ExpressionUnderCursor expressionUnderCursor;
+ ExpressionUnderCursor expressionUnderCursor(tokenCache());
const QString expression = expressionUnderCursor(tc);
TypeOfExpression typeOfExpression;
- typeOfExpression.setSnapshot(snapshot);
- QList<LookupItem> resolvedSymbols =
- typeOfExpression(expression, doc, lastSymbol);
+ typeOfExpression.init(doc, snapshot);
+ const QList<LookupItem> resolvedSymbols = typeOfExpression(expression, scope, TypeOfExpression::Preprocess);
if (!resolvedSymbols.isEmpty()) {
- LookupItem result = skipForwardDeclarations(resolvedSymbols);
+ const LookupItem result = skipForwardDeclarations(resolvedSymbols);
- if (Symbol *symbol = result.lastVisibleSymbol()) {
+ if (Symbol *symbol = result.declaration()) {
Symbol *def = 0;
- if (resolveTarget && !lastSymbol->isFunction())
- def = findDefinition(symbol);
+
+ if (resolveTarget) {
+ def = findDefinition(symbol, snapshot);
+
+ if (def == doc->lastVisibleSymbolAt(line, column))
+ def = 0; // jump to declaration then.
+ }
link = linkToSymbol(def ? def : symbol);
link.begin = beginOfToken;
openLink(findLinkAt(textCursor()));
}
-Symbol *CPPEditor::findDefinition(Symbol *symbol)
+Symbol *CPPEditor::findDefinition(Symbol *symbol, const Snapshot &snapshot)
{
if (symbol->isFunction())
return 0; // symbol is a function definition.
- Function *funTy = symbol->type()->asFunctionType();
- if (! funTy)
- return 0; // symbol does not have function type.
-
- const Name *name = symbol->name();
- if (! name)
- return 0; // skip anonymous functions!
-
- if (const QualifiedNameId *q = name->asQualifiedNameId())
- name = q->unqualifiedNameId();
-
- // map from file names to function definitions.
- QMap<QString, QList<Function *> > functionDefinitions;
-
- // find function definitions.
- FindFunctionDefinitions findFunctionDefinitions;
-
- // save the current snapshot
- const Snapshot snapshot = m_modelManager->snapshot();
-
- foreach (Document::Ptr doc, snapshot) {
- if (Scope *globals = doc->globalSymbols()) {
- QList<Function *> *localFunctionDefinitions =
- &functionDefinitions[doc->fileName()];
+ else if (! symbol->type()->isFunctionType())
+ return 0; // not a function declaration
- findFunctionDefinitions(name, globals,
- localFunctionDefinitions);
- }
- }
-
- // a dummy document.
- Document::Ptr expressionDocument = Document::create("<empty>");
-
- Function *bestMatch = 0;
- int bestScore = -1;
-
- QMapIterator<QString, QList<Function *> > it(functionDefinitions);
- while (it.hasNext()) {
- it.next();
-
- // get the instance of the document.
- Document::Ptr thisDocument = snapshot.document(it.key());
-
- foreach (Function *f, it.value()) {
- int score = 0; // current function's score
-
- const int funTyArgsCount = funTy->argumentCount();
- const int fArgsCount = f->argumentCount();
-
- // max score if arguments count equals
- if (funTyArgsCount == fArgsCount)
- score += funTyArgsCount + 1;
- else
- score += (funTyArgsCount < fArgsCount) ? funTyArgsCount : fArgsCount;
-
- // +1 to score for every equal parameter
- unsigned minCount = (funTyArgsCount < fArgsCount) ? funTyArgsCount : fArgsCount;
- for (unsigned i = 0; i < minCount; ++i)
- if (Symbol *funTyArg = funTy->argumentAt(i))
- if (Symbol *fArg = f->argumentAt(i))
- if (funTyArg->type().isEqualTo(fArg->type()))
- score++;
-
- if (score > bestScore) {
- // create a lookup context
- const LookupContext context(f, expressionDocument,
- thisDocument, snapshot);
-
- // search the matching definition for the function declaration `symbol'.
- foreach (Symbol *s, context.resolve(f->name())) {
- if (s == symbol) {
- bestMatch = f;
- bestScore = score;
- }
- }
- }
- }
- }
-
- return bestMatch;
+ return snapshot.findMatchingDefinition(symbol);
}
unsigned CPPEditor::editorRevision() const
QString CPPEditor::insertMatchingBrace(const QTextCursor &tc, const QString &text,
QChar la, int *skippedChars) const
{
- MatchingText m;
+ MatchingText m(tokenCache());
return m.insertMatchingBrace(tc, text, la, skippedChars);
}
QString CPPEditor::insertParagraphSeparator(const QTextCursor &tc) const
{
- MatchingText m;
+ MatchingText m(tokenCache());
return m.insertParagraphSeparator(tc);
}
bool CPPEditor::isInComment(const QTextCursor &cursor) const
{
- CPlusPlus::TokenUnderCursor tokenUnderCursor;
- const SimpleToken tk = tokenUnderCursor(cursor);
+ const SimpleToken tk = tokenCache()->tokenUnderCursor(cursor);
if (tk.isComment()) {
const int pos = cursor.selectionEnd() - cursor.block().position();
}
// 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)
+ const QTextBlock &block,
+ const TextEditor::TextBlockIterator &programBegin,
+ const TextEditor::TextBlockIterator &programEnd,
+ QChar typedChar)
{
- typedef typename SharedTools::Indenter<Iterator> Indenter;
+ typedef SharedTools::Indenter Indenter;
Indenter &indenter = Indenter::instance();
indenter.setIndentSize(ts.m_indentSize);
indenter.setTabSize(ts.m_tabSize);
const TabSettings &ts = tabSettings();
- BackwardsScanner tk(tc, QString(), 400);
+ BackwardsScanner tk(tokenCache(), tc, 400);
const int tokenCount = tk.startToken();
if (tokenCount != 0) {
void CPPEditor::performQuickFix(int index)
{
- CPPQuickFixCollector *quickFixCollector = CppPlugin::instance()->quickFixCollector();
- QuickFixOperationPtr op = m_quickFixes.at(index);
- quickFixCollector->perform(op);
- //op->createChangeSet();
- //setChangeSet(op->changeSet());
+ TextEditor::QuickFixOperation::Ptr op = m_quickFixes.at(index);
+ op->perform();
}
void CPPEditor::contextMenuEvent(QContextMenuEvent *e)
Core::ActionContainer *mcontext = am->actionContainer(CppEditor::Constants::M_CONTEXT);
QMenu *contextMenu = mcontext->menu();
- CPPQuickFixCollector *quickFixCollector = CppPlugin::instance()->quickFixCollector();
+ CppQuickFixCollector *quickFixCollector = CppPlugin::instance()->quickFixCollector();
QSignalMapper mapper;
connect(&mapper, SIGNAL(mapped(int)), this, SLOT(performQuickFix(int)));
m_quickFixes = quickFixCollector->quickFixes();
for (int index = 0; index < m_quickFixes.size(); ++index) {
- QuickFixOperationPtr op = m_quickFixes.at(index);
+ TextEditor::QuickFixOperation::Ptr op = m_quickFixes.at(index);
QAction *action = menu->addAction(op->description());
mapper.setMapping(action, index);
connect(action, SIGNAL(triggered()), &mapper, SLOT(map()));
m_occurrencesUnusedFormat.clearForeground();
m_occurrencesUnusedFormat.setToolTip(tr("Unused variable"));
m_occurrenceRenameFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_OCCURRENCES_RENAME));
+ m_typeFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_TYPE));
// only set the background, we do not want to modify foreground properties set by the syntax highlighter or the link
m_occurrencesFormat.clearForeground();
return;
}
- m_lastSemanticInfo = semanticInfo;
+ const SemanticInfo previousSemanticInfo = m_lastSemanticInfo;
+ m_lastSemanticInfo = semanticInfo; // update the semantic info
int line = 0, column = 0;
convertPosition(position(), &line, &column);
highlightUses(uses, semanticInfo, &m_renameSelections);
}
+ if (m_lastSemanticInfo.forced || previousSemanticInfo.revision != semanticInfo.revision) {
+ QList<QTextEdit::ExtraSelection> undefinedSymbolSelections;
+ foreach (const Document::DiagnosticMessage &m, semanticInfo.diagnosticMessages) {
+ QTextCursor cursor(document());
+ cursor.setPosition(document()->findBlockByNumber(m.line() - 1).position() + m.column() - 1);
+ cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, m.length());
+
+ QTextEdit::ExtraSelection sel;
+ sel.cursor = cursor;
+ sel.format.setUnderlineColor(Qt::darkYellow); // ### hardcoded
+ sel.format.setUnderlineStyle(QTextCharFormat::WaveUnderline); // ### hardcoded
+ sel.format.setToolTip(m.text());
+ undefinedSymbolSelections.append(sel);
+ }
+
+ setExtraSelections(UndefinedSymbolSelection, undefinedSymbolSelections);
+
+ QTextBlock currentBlock = document()->firstBlock();
+ unsigned currentLine = 1;
+
+ QList<QTextEdit::ExtraSelection> typeSelections;
+
+ foreach (const SemanticInfo::Use &use, semanticInfo.typeUsages) {
+ QTextCursor cursor(document());
+
+ if (currentLine != use.line) {
+ int delta = use.line - currentLine;
+
+ if (delta >= 0) {
+ while (delta--)
+ currentBlock = currentBlock.next();
+ } else {
+ currentBlock = document()->findBlockByNumber(use.line - 1);
+ }
+
+ currentLine = use.line;
+ }
+
+ cursor.setPosition(currentBlock.position() + use.column - 1);
+ cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, use.length);
+
+ QTextEdit::ExtraSelection sel;
+ sel.cursor = cursor;
+ sel.format = m_typeFormat;
+ typeSelections.append(sel);
+ }
+
+ setExtraSelections(TypeSelection, typeSelections);
+ }
+
setExtraSelections(UnusedSymbolSelection, unusedSelections);
- setExtraSelections(CodeSemanticsSelection, m_renameSelections);
+
+ if (! m_renameSelections.isEmpty())
+ setExtraSelections(CodeSemanticsSelection, m_renameSelections); // ###
+ else {
+ FindCanonicalSymbol cs(this, semanticInfo);
+ markSymbols(cs(textCursor()), semanticInfo);
+ }
+
+ m_lastSemanticInfo.forced = false; // clear the forced flag
}
SemanticHighlighter::Source CPPEditor::currentSource(bool force)
Snapshot snapshot;
Document::Ptr doc;
+ QList<Document::DiagnosticMessage> diagnosticMessages;
+ QList<SemanticInfo::Use> typeUsages;
+ LookupContext context;
if (! source.force && revision == source.revision) {
m_mutex.lock();
- snapshot = m_lastSemanticInfo.snapshot;
+ snapshot = m_lastSemanticInfo.snapshot; // ### TODO: use the new snapshot.
doc = m_lastSemanticInfo.doc;
+ diagnosticMessages = m_lastSemanticInfo.diagnosticMessages;
+ typeUsages = m_lastSemanticInfo.typeUsages;
+ context = m_lastSemanticInfo.context;
m_mutex.unlock();
}
if (! doc) {
- const QByteArray preprocessedCode = source.snapshot.preprocessedCode(source.code, source.fileName);
-
snapshot = source.snapshot;
- doc = source.snapshot.documentFromSource(preprocessedCode, source.fileName);
+ const QByteArray preprocessedCode = snapshot.preprocessedCode(source.code, source.fileName);
+
+ doc = snapshot.documentFromSource(preprocessedCode, source.fileName);
doc->check();
+
+ context = LookupContext(doc, snapshot);
+
+ if (TranslationUnit *unit = doc->translationUnit()) {
+ CheckUndefinedSymbols checkUndefinedSymbols(unit, context);
+ diagnosticMessages = checkUndefinedSymbols(unit->ast());
+ typeUsages.clear();
+ foreach (const CheckUndefinedSymbols::Use &use, checkUndefinedSymbols.typeUsages()) // ### remove me
+ typeUsages.append(SemanticInfo::Use(use.line, use.column, use.length));
+ }
}
TranslationUnit *translationUnit = doc->translationUnit();
semanticInfo.localUses = useTable.localUses;
semanticInfo.hasQ = useTable.hasQ;
semanticInfo.hasD = useTable.hasD;
+ semanticInfo.forced = source.force;
+ semanticInfo.diagnosticMessages = diagnosticMessages;
+ semanticInfo.typeUsages = typeUsages;
+ semanticInfo.context = context;
return semanticInfo;
}
#include "cppeditorenums.h"
#include "cppquickfix.h"
#include <cplusplus/CppDocument.h>
+#include <cplusplus/LookupContext.h>
#include <texteditor/basetexteditor.h>
#include <QtCore/QThread>
namespace CPlusPlus {
class OverviewModel;
class Symbol;
+class TokenCache;
}
namespace CppTools {
typedef QHashIterator<CPlusPlus::Symbol *, QList<Use> > LocalUseIterator;
SemanticInfo()
- : revision(0), hasQ(false), hasD(false)
+ : revision(0), hasQ(false), hasD(false), forced(false)
{ }
unsigned revision;
bool hasQ: 1;
bool hasD: 1;
- CPlusPlus::Snapshot snapshot;
- CPlusPlus::Document::Ptr doc;
- LocalUseMap localUses;
+ bool forced: 1;
+ CPlusPlus::Snapshot snapshot; // ### remove
+ CPlusPlus::Document::Ptr doc; // ### remove
+ CPlusPlus::LookupContext context;
+ LocalUseMap localUses; // ### rename
+ QList<Use> typeUsages;
+ QList<CPlusPlus::Document::DiagnosticMessage> diagnosticMessages;
};
class SemanticHighlighter: public QThread
virtual void paste(); // reimplemented from BaseTextEditor
virtual void cut(); // reimplemented from BaseTextEditor
+ CPlusPlus::TokenCache *tokenCache() const;
+
+ CppTools::CppModelManagerInterface *modelManager() const;
+
public Q_SLOTS:
virtual void setFontSettings(const TextEditor::FontSettings &);
void setSortedMethodOverview(bool sort);
virtual bool isInComment(const QTextCursor &cursor) const;
- CPlusPlus::Symbol *findCanonicalSymbol(const QTextCursor &cursor,
- CPlusPlus::Document::Ptr doc,
- const CPlusPlus::Snapshot &snapshot) const;
const CPlusPlus::Macro *findCanonicalMacro(const QTextCursor &cursor,
CPlusPlus::Document::Ptr doc) const;
bool showWarningMessage() const;
void setShowWarningMessage(bool showWarningMessage);
- CPlusPlus::Symbol *markSymbols();
+ void markSymbols(CPlusPlus::Symbol *canonicalSymbol, const SemanticInfo &info);
bool sortedMethodOverview() const;
- CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol);
+ CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol, const CPlusPlus::Snapshot &snapshot);
virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
TextEditor::ITextEditor *openCppEditorAt(const QString &fileName, int line,
QTextCharFormat m_occurrencesFormat;
QTextCharFormat m_occurrencesUnusedFormat;
QTextCharFormat m_occurrenceRenameFormat;
+ QTextCharFormat m_typeFormat;
QList<QTextEdit::ExtraSelection> m_renameSelections;
int m_currentRenameSelection;
SemanticHighlighter *m_semanticHighlighter;
SemanticInfo m_lastSemanticInfo;
- QList<QuickFixOperationPtr> m_quickFixes;
+ QList<TextEditor::QuickFixOperation::Ptr> m_quickFixes;
bool m_initialized;
};
cppeditor_global.h \
cppclasswizard.h \
cppquickfix.h
+
SOURCES += cppplugin.cpp \
cppeditor.cpp \
cpphighlighter.cpp \
cppfilewizard.cpp \
cppclasswizard.cpp \
cppquickfix.cpp
+
RESOURCES += cppeditor.qrc
OTHER_FILES += CppEditor.pluginspec CppEditor.mimetypes.xml
const QList<SimpleToken> tokens = tokenize(text, initialState);
state = tokenize.state(); // refresh the state
+ int foldingIndent = initialBraceDepth;
+ if (TextBlockUserData *userData = BaseTextDocumentLayout::testUserData(currentBlock())) {
+ userData->setFoldingIndent(0);
+ userData->setFoldingStartIncluded(false);
+ userData->setFoldingEndIncluded(false);
+ }
+
if (tokens.isEmpty()) {
setCurrentBlockState(previousState);
- if (TextBlockUserData *userData = BaseTextDocumentLayout::testUserData(currentBlock())) {
- userData->setClosingCollapseMode(TextBlockUserData::NoClosingCollapse);
- userData->setCollapseMode(TextBlockUserData::NoCollapse);
- }
BaseTextDocumentLayout::clearParentheses(currentBlock());
if (text.length()) // the empty line can still contain whitespace
setFormat(0, text.length(), m_formats[CppVisualWhitespace]);
+ BaseTextDocumentLayout::setFoldingIndent(currentBlock(), foldingIndent);
return;
}
}
if (tk.is(T_LPAREN) || tk.is(T_LBRACE) || tk.is(T_LBRACKET)) {
- const QChar c(tk.text().at(0));
+ const QChar c = text.at(tk.position());
parentheses.append(Parenthesis(Parenthesis::Opened, c, tk.position()));
- if (tk.is(T_LBRACE))
+ if (tk.is(T_LBRACE)) {
++braceDepth;
+
+ // if a folding block opens at the beginning of a line, treat the entire line
+ // as if it were inside the folding block
+ if (tk.position() == firstNonSpace) {
+ ++foldingIndent;
+ BaseTextDocumentLayout::userData(currentBlock())->setFoldingStartIncluded(true);
+ }
+ }
} else if (tk.is(T_RPAREN) || tk.is(T_RBRACE) || tk.is(T_RBRACKET)) {
- const QChar c(tk.text().at(0));
+ const QChar c = text.at(tk.position());
parentheses.append(Parenthesis(Parenthesis::Closed, c, tk.position()));
- if (tk.is(T_RBRACE))
+ if (tk.is(T_RBRACE)) {
--braceDepth;
+ if (braceDepth < foldingIndent) {
+ // unless we are at the end of the block, we reduce the folding indent
+ if (i == tokens.size()-1 || tokens.at(i+1).is(T_SEMICOLON))
+ BaseTextDocumentLayout::userData(currentBlock())->setFoldingEndIncluded(true);
+ else
+ foldingIndent = qMin(braceDepth, foldingIndent);
+ }
+ }
}
bool highlightCurrentWordAsPreprocessor = highlightAsPreprocessor;
highlightAsPreprocessor = true;
} else if (highlightCurrentWordAsPreprocessor &&
- (tk.isKeyword() || tk.is(T_IDENTIFIER)) && isPPKeyword(tk.text()))
+ (tk.isKeyword() || tk.is(T_IDENTIFIER)) && isPPKeyword(text.midRef(tk.position(), tk.length())))
setFormat(tk.position(), tk.length(), m_formats[CppPreprocessorFormat]);
else if (tk.is(T_NUMERIC_LITERAL))
// - is not a continuation line (tokens.size() > 1 || ! state)
if (initialState && i == 0 && (tokens.size() > 1 || ! state)) {
--braceDepth;
-
+ // unless we are at the end of the block, we reduce the folding indent
+ if (i == tokens.size()-1)
+ BaseTextDocumentLayout::userData(currentBlock())->setFoldingEndIncluded(true);
+ else
+ foldingIndent = qMin(braceDepth, foldingIndent);
const int tokenEnd = tk.position() + tk.length() - 1;
parentheses.append(Parenthesis(Parenthesis::Closed, QLatin1Char('-'), tokenEnd));
initialState = 0;
}
- } else if (tk.isKeyword() || isQtKeyword(tk.text()) || tk.isObjCAtKeyword() || tk.isObjCTypeQualifier())
+ } else if (tk.isKeyword() || isQtKeyword(text.midRef(tk.position(), tk.length())) || tk.isObjCAtKeyword() || tk.isObjCTypeQualifier())
setFormat(tk.position(), tk.length(), m_formats[CppKeywordFormat]);
else if (tk.isOperator())
setFormat(tk.position(), tk.length(), m_formats[CppLabelFormat]);
else if (tk.is(T_IDENTIFIER))
- highlightWord(tk.text(), tk.position(), tk.length());
+ highlightWord(text.midRef(tk.position(), tk.length()), tk.position(), tk.length());
+
}
// mark the trailing white spaces
highlightLine(text, lastTokenEnd, text.length() - lastTokenEnd, QTextCharFormat());
}
- if (TextBlockUserData *userData = BaseTextDocumentLayout::testUserData(currentBlock())) {
- userData->setClosingCollapseMode(TextBlockUserData::NoClosingCollapse);
- userData->setCollapseMode(TextBlockUserData::NoCollapse);
- }
-
if (! initialState && state && ! tokens.isEmpty()) {
parentheses.append(Parenthesis(Parenthesis::Opened, QLatin1Char('+'),
tokens.last().position()));
++braceDepth;
}
- QChar c;
- int collapse = Parenthesis::collapseAtPos(parentheses, &c);
- if (collapse >= 0) {
- TextBlockUserData::CollapseMode collapseMode = TextBlockUserData::CollapseAfter;
- if (collapse == firstNonSpace && c != QLatin1Char('+'))
- collapseMode = TextBlockUserData::CollapseThis;
- BaseTextDocumentLayout::userData(currentBlock())->setCollapseMode(collapseMode);
- }
-
-
- int cc = Parenthesis::closeCollapseAtPos(parentheses);
- if (cc >= 0) {
- TextBlockUserData *userData = BaseTextDocumentLayout::userData(currentBlock());
- userData->setClosingCollapseMode(TextBlockUserData::ClosingCollapse);
- QString trailingText = text.mid(cc+1).simplified();
- if (trailingText.isEmpty() || trailingText == QLatin1String(";")) {
- userData->setClosingCollapseMode(TextBlockUserData::ClosingCollapseAtEnd);
- }
- }
-
BaseTextDocumentLayout::setParentheses(currentBlock(), parentheses);
// if the block is ifdefed out, we only store the parentheses, but
+
// do not adjust the brace depth.
- if (BaseTextDocumentLayout::ifdefedOut(currentBlock()))
+ if (BaseTextDocumentLayout::ifdefedOut(currentBlock())) {
braceDepth = initialBraceDepth;
+ foldingIndent = initialBraceDepth;
+ }
+
+ BaseTextDocumentLayout::setFoldingIndent(currentBlock(), foldingIndent);
// optimization: if only the brace depth changes, we adjust subsequent blocks
// to have QSyntaxHighlighter stop the rehighlighting
QTextBlock block = currentBlock().next();
while (block.isValid() && block.userState() != -1) {
BaseTextDocumentLayout::changeBraceDepth(block, delta);
+ BaseTextDocumentLayout::changeFoldingIndent(block, delta);
block = block.next();
}
}
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]);
+
+ if (word.length() > 2 && word.at(0) == QLatin1Char('Q')) {
+ if (word.at(1) == QLatin1Char('_') // Q_
+ || word.at(1) == QLatin1Char('T') && word.at(2) == QLatin1Char('_')) { // QT_
+ for (int i = 1; i < word.length(); ++i) {
+ const QChar &ch = word.at(i);
+ if (! (ch.isUpper() || ch == QLatin1Char('_')))
+ return;
+ }
+
+ setFormat(position, length, m_formats[CppTypeFormat]);
+ }
}
}
}
}
-static QString buildHelpId(Symbol *symbol, const Name *name)
+static QString buildHelpId(Symbol *symbol, const Name *declarationName)
{
Scope *scope = 0;
if (symbol) {
scope = symbol->scope();
- name = symbol->name();
+ declarationName = symbol->name();
}
- if (! name)
+ if (! declarationName)
return QString();
Overview overview;
overview.setShowReturnTypes(false);
QStringList qualifiedNames;
- qualifiedNames.prepend(overview.prettyName(name));
+ qualifiedNames.prepend(overview.prettyName(declarationName));
for (; scope; scope = scope->enclosingScope()) {
Symbol *owner = scope->owner();
return qualifiedNames.join(QLatin1String("::"));
}
-// ### move me
-static FullySpecifiedType resolve(const FullySpecifiedType &ty,
- const LookupContext &context,
- Symbol **resolvedSymbol,
- const Name **resolvedName)
-{
- Control *control = context.control();
-
- if (const PointerType *ptrTy = ty->asPointerType()) {
- return control->pointerType(resolve(ptrTy->elementType(), context,
- resolvedSymbol, resolvedName));
-
- } else if (const ReferenceType *refTy = ty->asReferenceType()) {
- return control->referenceType(resolve(refTy->elementType(), context,
- resolvedSymbol, resolvedName));
-
- } else if (const PointerToMemberType *ptrToMemTy = ty->asPointerToMemberType()) {
- return control->pointerToMemberType(ptrToMemTy->memberName(),
- resolve(ptrToMemTy->elementType(), context,
- resolvedSymbol, resolvedName));
-
- } else if (const NamedType *namedTy = ty->asNamedType()) {
- if (resolvedName)
- *resolvedName = namedTy->name();
-
- const QList<Symbol *> candidates = context.resolve(namedTy->name());
-
- foreach (Symbol *c, candidates) {
- if (c->isClass() || c->isEnum()) {
- if (resolvedSymbol)
- *resolvedSymbol = c;
-
- return c->type();
- }
- }
-
- } else if (const Namespace *nsTy = ty->asNamespaceType()) {
- if (resolvedName)
- *resolvedName = nsTy->name();
-
- if (resolvedSymbol)
- *resolvedSymbol = const_cast<Namespace *>(nsTy);
-
- } else if (const Class *classTy = ty->asClassType()) {
- if (resolvedName)
- *resolvedName = classTy->name();
-
- if (resolvedSymbol)
- *resolvedSymbol = const_cast<Class *>(classTy);
-
- } else if (const ForwardClassDeclaration *fwdClassTy = ty->asForwardClassDeclarationType()) {
- if (resolvedName)
- *resolvedName = fwdClassTy->name();
-
- if (resolvedSymbol)
- *resolvedSymbol = const_cast<ForwardClassDeclaration *>(fwdClassTy);
-
- } else if (const Enum *enumTy = ty->asEnumType()) {
- if (resolvedName)
- *resolvedName = enumTy->name();
-
- if (resolvedSymbol)
- *resolvedSymbol = const_cast<Enum *>(enumTy);
-
- } else if (const Function *funTy = ty->asFunctionType()) {
- if (resolvedName)
- *resolvedName = funTy->name();
-
- if (resolvedSymbol)
- *resolvedSymbol = const_cast<Function *>(funTy);
-
- }
-
- return ty;
-}
-
void CppHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, int pos)
{
m_helpId.clear();
if (!edit)
return;
- const Snapshot documents = m_modelManager->snapshot();
+ const Snapshot snapshot = m_modelManager->snapshot();
const QString fileName = editor->file()->fileName();
- Document::Ptr doc = documents.document(fileName);
+ Document::Ptr doc = snapshot.document(fileName);
if (!doc)
return; // nothing to do
// Find the last symbol up to the cursor position
int line = 0, column = 0;
editor->convertPosition(tc.position(), &line, &column);
- Symbol *lastSymbol = doc->findSymbolAt(line, column);
+ Scope *scope = doc->scopeAt(line, column);
TypeOfExpression typeOfExpression;
- typeOfExpression.setSnapshot(documents);
+ typeOfExpression.init(doc, snapshot);
// We only want to show F1 if the tooltip matches the help id
bool showF1 = true;
}
// Fetch the expression's code
- ExpressionUnderCursor expressionUnderCursor;
+ ExpressionUnderCursor expressionUnderCursor(m_modelManager->tokenCache(editor));
const QString expression = expressionUnderCursor(tc);
- const QList<LookupItem> types = typeOfExpression(expression, doc, lastSymbol);
+ const QList<LookupItem> types = typeOfExpression(expression, scope);
- if (!types.isEmpty()) {
- const LookupItem result = types.first();
- FullySpecifiedType firstType = result.type(); // result of `type of expression'.
- Symbol *lookupSymbol = result.lastVisibleSymbol(); // lookup symbol
-
- Symbol *resolvedSymbol = lookupSymbol;
- const Name *resolvedName = lookupSymbol ? lookupSymbol->name() : 0;
- firstType = resolve(firstType, typeOfExpression.lookupContext(),
- &resolvedSymbol, &resolvedName);
-
- if (resolvedSymbol && resolvedSymbol->scope()
- && resolvedSymbol->scope()->isClassScope()) {
- Class *enclosingClass = resolvedSymbol->scope()->owner()->asClass();
+ if (!types.isEmpty()) {
+ Overview overview;
+ overview.setShowArgumentNames(true);
+ overview.setShowReturnTypes(true);
+ overview.setShowFullyQualifiedNamed(true);
+
+ const LookupItem result = types.first(); // ### TODO: select the best candidate.
+ FullySpecifiedType symbolTy = result.type(); // result of `type of expression'.
+ Symbol *declaration = result.declaration(); // lookup symbol
+ const Name *declarationName = declaration ? declaration->name() : 0;
+
+ if (declaration && declaration->scope()
+ && declaration->scope()->isClassScope()) {
+ Class *enclosingClass = declaration->scope()->owner()->asClass();
if (const Identifier *id = enclosingClass->identifier()) {
- if (id->isEqualTo(resolvedSymbol->identifier()))
- resolvedSymbol = enclosingClass;
+ if (id->isEqualTo(declaration->identifier()))
+ declaration = enclosingClass;
}
}
- m_helpId = buildHelpId(resolvedSymbol, resolvedName);
+ m_helpId = buildHelpId(declaration, declarationName);
if (m_toolTip.isEmpty()) {
- Symbol *symbol = result.lastVisibleSymbol();
- if (resolvedSymbol)
- symbol = resolvedSymbol;
+ Symbol *symbol = declaration;
- Overview overview;
- overview.setShowArgumentNames(true);
- overview.setShowReturnTypes(true);
- overview.setShowFullyQualifiedNamed(true);
+ if (declaration)
+ symbol = declaration;
- if (symbol && symbol == resolvedSymbol && symbol->isClass()) {
+ if (symbol && symbol == declaration && symbol->isClass()) {
m_toolTip = m_helpId;
- } else if (lookupSymbol && (lookupSymbol->isDeclaration() || lookupSymbol->isArgument())) {
- m_toolTip = overview.prettyType(firstType, buildHelpId(lookupSymbol, lookupSymbol->name()));
+ } else if (declaration && (declaration->isDeclaration() || declaration->isArgument())) {
+ m_toolTip = overview.prettyType(symbolTy, buildHelpId(declaration, declaration->name()));
- } else if (firstType->isClassType() || firstType->isEnumType() ||
- firstType->isForwardClassDeclarationType()) {
+ } else if (symbolTy->isClassType() || symbolTy->isEnumType() ||
+ symbolTy->isForwardClassDeclarationType()) {
m_toolTip = m_helpId;
} else {
- m_toolTip = overview.prettyType(firstType, m_helpId);
+ m_toolTip = overview.prettyType(symbolTy, m_helpId);
}
}
class QPoint;
QT_END_NAMESPACE
+namespace CPlusPlus {
+class TokenCache;
+}
+
namespace Core {
class IEditor;
}
return m_sortedMethodOverview;
}
-CPPQuickFixCollector *CppPlugin::quickFixCollector() const
+CppQuickFixCollector *CppPlugin::quickFixCollector() const
{ return m_quickFixCollector; }
bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
addAutoReleasedObject(new CppEditorFactory(this));
addAutoReleasedObject(new CppHoverHandler);
- m_quickFixCollector = new CPPQuickFixCollector;
+ m_quickFixCollector = new CppQuickFixCollector;
addAutoReleasedObject(m_quickFixCollector);
CppFileWizard::BaseFileWizardParameters wizardParameters(Core::IWizard::FileWizard);
namespace Internal {
class CPPEditor;
-class CPPQuickFixCollector;
+class CppQuickFixCollector;
class CppPlugin : public ExtensionSystem::IPlugin
{
bool sortedMethodOverview() const;
- CPPQuickFixCollector *quickFixCollector() const;
+ CppQuickFixCollector *quickFixCollector() const;
signals:
void methodOverviewSortingChanged(bool sort);
QAction *m_findUsagesAction;
QAction *m_updateCodeModelAction;
- CPPQuickFixCollector *m_quickFixCollector;
+ CppQuickFixCollector *m_quickFixCollector;
QTimer *m_quickFixTimer;
QPointer<TextEditor::ITextEditable> m_currentTextEditable;
#include "cppquickfix.h"
#include "cppeditor.h"
+#include <cplusplus/ASTPath.h>
#include <cplusplus/CppDocument.h>
#include <cplusplus/ResolveExpression.h>
#include <Name.h>
#include <Literals.h>
+#include <cpptools/cpprefactoringchanges.h>
#include <cpptools/cpptoolsconstants.h>
#include <cpptools/cppmodelmanagerinterface.h>
using namespace CppEditor::Internal;
using namespace CPlusPlus;
+using namespace Utils;
namespace {
-class ASTPath: public ASTVisitor
+class CppQuickFixState: public TextEditor::QuickFixState
{
- Document::Ptr _doc;
- unsigned _line;
- unsigned _column;
- QList<AST *> _nodes;
-
public:
- ASTPath(Document::Ptr doc)
- : ASTVisitor(doc->translationUnit()),
- _doc(doc), _line(0), _column(0)
- {}
-
- QList<AST *> operator()(const QTextCursor &cursor)
- {
- _nodes.clear();
- _line = cursor.blockNumber() + 1;
- _column = cursor.columnNumber() + 1;
- accept(_doc->translationUnit()->ast());
- return _nodes;
- }
-
-#if 0
- // Useful for debugging:
- static void dump(const QList<AST *> nodes)
- {
- qDebug() << "ASTPath dump," << nodes.size() << "nodes:";
- for (int i = 0; i < nodes.size(); ++i)
- qDebug() << qPrintable(QString(i + 1, QLatin1Char('-'))) << typeid(*nodes.at(i)).name();
- }
-#endif
-
-protected:
- virtual bool preVisit(AST *ast)
- {
- unsigned firstToken = ast->firstToken();
- unsigned lastToken = ast->lastToken();
-
- if (firstToken > 0 && lastToken > firstToken) {
- unsigned startLine, startColumn;
- getTokenStartPosition(firstToken, &startLine, &startColumn);
-
- if (_line > startLine || (_line == startLine && _column >= startColumn)) {
-
- unsigned endLine, endColumn;
- getTokenEndPosition(lastToken - 1, &endLine, &endColumn);
-
- if (_line < endLine || (_line == endLine && _column <= endColumn)) {
- _nodes.append(ast);
- return true;
- }
- }
- }
-
- return false;
- }
+ QList<CPlusPlus::AST *> path;
+ SemanticInfo info;
};
/*
(a op b) -> !(a invop b)
!(a op b) -> (a invob b)
*/
-class UseInverseOp: public QuickFixOperation
+class UseInverseOp: public CppQuickFixOperation
{
public:
- UseInverseOp()
- : binary(0), nested(0), negation(0)
+ UseInverseOp(TextEditor::BaseTextEditor *editor)
+ : CppQuickFixOperation(editor), binary(0), nested(0), negation(0)
{}
virtual QString description() const
return index;
}
- virtual void createChangeSet()
+ virtual void createChanges()
{
+ ChangeSet changes;
if (negation) {
// can't remove parentheses since that might break precedence
- remove(negation->unary_op_token);
+ remove(&changes, negation->unary_op_token);
} else if (nested) {
- insert(startOf(nested), "!");
+ changes.insert(startOf(nested), "!");
} else {
- insert(startOf(binary), "!(");
- insert(endOf(binary), ")");
+ changes.insert(startOf(binary), "!(");
+ changes.insert(endOf(binary), ")");
}
- replace(binary->binary_op_token, replacement);
+ replace(&changes, binary->binary_op_token, replacement);
+ cppRefactoringChanges()->changeFile(fileName(), changes);
}
private:
As
b flipop a
*/
-class FlipBinaryOp: public QuickFixOperation
+class FlipBinaryOp: public CppQuickFixOperation
{
public:
- FlipBinaryOp()
- : binary(0)
+ FlipBinaryOp(TextEditor::BaseTextEditor *editor)
+ : CppQuickFixOperation(editor), binary(0)
{}
return index;
}
- virtual void createChangeSet()
+ virtual void createChanges()
{
- flip(binary->left_expression, binary->right_expression);
+ ChangeSet changes;
+
+ flip(&changes, binary->left_expression, binary->right_expression);
if (! replacement.isEmpty())
- replace(binary->binary_op_token, replacement);
+ replace(&changes, binary->binary_op_token, replacement);
+
+ cppRefactoringChanges()->changeFile(fileName(), changes);
}
private:
As
!(a || b)
*/
-class RewriteLogicalAndOp: public QuickFixOperation
+class RewriteLogicalAndOp: public CppQuickFixOperation
{
public:
- RewriteLogicalAndOp()
- : left(0), right(0), pattern(0)
+ RewriteLogicalAndOp(TextEditor::BaseTextEditor *editor)
+ : CppQuickFixOperation(editor), left(0), right(0), pattern(0)
{}
virtual QString description() const
return -1;
}
- virtual void createChangeSet()
+ virtual void createChanges()
{
- setTopLevelNode(pattern);
- replace(pattern->binary_op_token, QLatin1String("||"));
- remove(left->unary_op_token);
- remove(right->unary_op_token);
- insert(startOf(pattern), QLatin1String("!("));
- insert(endOf(pattern), QLatin1String(")"));
+ ChangeSet changes;
+ replace(&changes, pattern->binary_op_token, QLatin1String("||"));
+ remove(&changes, left->unary_op_token);
+ remove(&changes, right->unary_op_token);
+ const int start = startOf(pattern);
+ const int end = endOf(pattern);
+ changes.insert(start, QLatin1String("!("));
+ changes.insert(end, QLatin1String(")"));
+
+ cppRefactoringChanges()->changeFile(fileName(), changes);
+ cppRefactoringChanges()->reindent(fileName(), range(start, end));
}
private:
BinaryExpressionAST *pattern;
};
-class SplitSimpleDeclarationOp: public QuickFixOperation
+class SplitSimpleDeclarationOp: public CppQuickFixOperation
{
public:
- SplitSimpleDeclarationOp()
- : declaration(0)
+ SplitSimpleDeclarationOp(TextEditor::BaseTextEditor *editor)
+ : CppQuickFixOperation(editor), declaration(0)
{}
virtual QString description() const
return -1;
}
- virtual void createChangeSet()
+ virtual void createChanges()
{
- setTopLevelNode(declaration);
+ ChangeSet changes;
+
SpecifierListAST *specifiers = declaration->decl_specifier_list;
int declSpecifiersStart = startOf(specifiers->firstToken());
int declSpecifiersEnd = endOf(specifiers->lastToken() - 1);
for (DeclaratorListAST *it = declaration->declarator_list->next; it; it = it->next) {
DeclaratorAST *declarator = it->value;
- insert(insertPos, QLatin1String("\n"));
- copy(declSpecifiersStart, declSpecifiersEnd, insertPos);
- insert(insertPos, QLatin1String(" "));
- move(declarator, insertPos);
- insert(insertPos, QLatin1String(";"));
+ changes.insert(insertPos, QLatin1String("\n"));
+ changes.copy(declSpecifiersStart, declSpecifiersEnd - declSpecifiersStart, insertPos);
+ changes.insert(insertPos, QLatin1String(" "));
+ move(&changes, declarator, insertPos);
+ changes.insert(insertPos, QLatin1String(";"));
- remove(endOf(prevDeclarator), startOf(declarator));
+ const int prevDeclEnd = endOf(prevDeclarator);
+ changes.remove(prevDeclEnd, startOf(declarator) - prevDeclEnd);
prevDeclarator = declarator;
}
+
+ cppRefactoringChanges()->changeFile(fileName(), changes);
+ cppRefactoringChanges()->reindent(fileName(), range(startOf(declaration->firstToken()),
+ endOf(declaration->lastToken() - 1)));
}
private:
Add curly braces to a if statement that doesn't already contain a
compound statement.
*/
-class AddBracesToIfOp: public QuickFixOperation
+class AddBracesToIfOp: public CppQuickFixOperation
{
public:
- AddBracesToIfOp()
- : _statement(0)
+ AddBracesToIfOp(TextEditor::BaseTextEditor *editor)
+ : CppQuickFixOperation(editor), _statement(0)
{}
virtual QString description() const
return -1;
}
- virtual void createChangeSet()
+ virtual void createChanges()
{
- setTopLevelNode(_statement);
- insert(endOf(_statement->firstToken() - 1), QLatin1String(" {"));
- insert(endOf(_statement->lastToken() - 1), "\n}");
+ ChangeSet changes;
+
+ const int start = endOf(_statement->firstToken() - 1);
+ changes.insert(start, QLatin1String(" {"));
+
+ const int end = endOf(_statement->lastToken() - 1);
+ changes.insert(end, "\n}");
+
+ cppRefactoringChanges()->changeFile(fileName(), changes);
+ cppRefactoringChanges()->reindent(fileName(), range(start, end));
}
private:
Type name = foo;
if (name) {...}
*/
-class MoveDeclarationOutOfIfOp: public QuickFixOperation
+class MoveDeclarationOutOfIfOp: public CppQuickFixOperation
{
public:
- MoveDeclarationOutOfIfOp()
- : condition(0), pattern(0), core(0)
+ MoveDeclarationOutOfIfOp(TextEditor::BaseTextEditor *editor)
+ : CppQuickFixOperation(editor), condition(0), pattern(0), core(0)
{}
virtual QString description() const
return -1;
}
- virtual void createChangeSet()
+ virtual void createChanges()
{
- setTopLevelNode(pattern);
+ ChangeSet changes;
- copy(core, startOf(condition));
+ copy(&changes, core, startOf(condition));
int insertPos = startOf(pattern);
- move(condition, insertPos);
- insert(insertPos, QLatin1String(";\n"));
+ move(&changes, condition, insertPos);
+ changes.insert(insertPos, QLatin1String(";\n"));
+
+ cppRefactoringChanges()->changeFile(fileName(), changes);
+ cppRefactoringChanges()->reindent(fileName(), range(startOf(pattern),
+ endOf(pattern)));
}
private:
Type name;
while ((name = foo()) != 0) {...}
*/
-class MoveDeclarationOutOfWhileOp: public QuickFixOperation
+class MoveDeclarationOutOfWhileOp: public CppQuickFixOperation
{
public:
- MoveDeclarationOutOfWhileOp()
- : condition(0), pattern(0), core(0)
+ MoveDeclarationOutOfWhileOp(TextEditor::BaseTextEditor *editor)
+ : CppQuickFixOperation(editor), condition(0), pattern(0), core(0)
{}
virtual QString description() const
return -1;
}
- virtual void createChangeSet()
+ virtual void createChanges()
{
- setTopLevelNode(pattern);
+ ChangeSet changes;
- insert(startOf(condition), QLatin1String("("));
- insert(endOf(condition), QLatin1String(") != 0"));
+ changes.insert(startOf(condition), QLatin1String("("));
+ changes.insert(endOf(condition), QLatin1String(") != 0"));
int insertPos = startOf(pattern);
- move(startOf(condition), startOf(core), insertPos);
- copy(core, insertPos);
- insert(insertPos, QLatin1String(";\n"));
+ const int conditionStart = startOf(condition);
+ changes.move(conditionStart, startOf(core) - conditionStart, insertPos);
+ copy(&changes, core, insertPos);
+ changes.insert(insertPos, QLatin1String(";\n"));
+
+ cppRefactoringChanges()->changeFile(fileName(), changes);
+ cppRefactoringChanges()->reindent(fileName(), range(startOf(pattern),
+ endOf(pattern)));
}
private:
else if (something_else)
x;
*/
-class SplitIfStatementOp: public QuickFixOperation
+class SplitIfStatementOp: public CppQuickFixOperation
{
public:
- SplitIfStatementOp()
- : condition(0), pattern(0)
+ SplitIfStatementOp(TextEditor::BaseTextEditor *editor)
+ : CppQuickFixOperation(editor), condition(0), pattern(0)
{}
virtual QString description() const
return -1;
}
- virtual void createChangeSet()
+ virtual void createChanges()
{
Token binaryToken = tokenAt(condition->binary_op_token);
void splitAndCondition()
{
- setTopLevelNode(pattern);
+ ChangeSet changes;
int startPos = startOf(pattern);
- insert(startPos, QLatin1String("if ("));
- move(condition->left_expression, startPos);
- insert(startPos, QLatin1String(") {\n"));
-
- remove(endOf(condition->left_expression), startOf(condition->right_expression));
- insert(endOf(pattern), QLatin1String("\n}"));
+ changes.insert(startPos, QLatin1String("if ("));
+ move(&changes, condition->left_expression, startPos);
+ changes.insert(startPos, QLatin1String(") {\n"));
+
+ const int lExprEnd = endOf(condition->left_expression);
+ changes.remove(lExprEnd,
+ startOf(condition->right_expression) - lExprEnd);
+ changes.insert(endOf(pattern), QLatin1String("\n}"));
+
+ cppRefactoringChanges()->changeFile(fileName(), changes);
+ cppRefactoringChanges()->reindent(fileName(), range(startOf(pattern),
+ endOf(pattern)));
}
void splitOrCondition()
{
+ ChangeSet changes;
+
StatementAST *ifTrueStatement = pattern->statement;
CompoundStatementAST *compoundStatement = ifTrueStatement->asCompoundStatement();
- setTopLevelNode(pattern);
-
int insertPos = endOf(ifTrueStatement);
if (compoundStatement)
- insert(insertPos, QLatin1String(" "));
+ changes.insert(insertPos, QLatin1String(" "));
else
- insert(insertPos, QLatin1String("\n"));
- insert(insertPos, QLatin1String("else if ("));
- move(startOf(condition->right_expression), startOf(pattern->rparen_token), insertPos);
- insert(insertPos, QLatin1String(")"));
- copy(endOf(pattern->rparen_token), endOf(pattern->statement), insertPos);
+ changes.insert(insertPos, QLatin1String("\n"));
+ changes.insert(insertPos, QLatin1String("else if ("));
+
+ const int rExprStart = startOf(condition->right_expression);
+ changes.move(rExprStart, startOf(pattern->rparen_token) - rExprStart,
+ insertPos);
+ changes.insert(insertPos, QLatin1String(")"));
+
+ const int rParenEnd = endOf(pattern->rparen_token);
+ changes.copy(rParenEnd, endOf(pattern->statement) - rParenEnd, insertPos);
- remove(endOf(condition->left_expression), startOf(condition->right_expression));
+ const int lExprEnd = endOf(condition->left_expression);
+ changes.remove(lExprEnd, startOf(condition->right_expression) - lExprEnd);
+
+ cppRefactoringChanges()->changeFile(fileName(), changes);
+ cppRefactoringChanges()->reindent(fileName(), range(startOf(pattern),
+ endOf(pattern)));
}
private:
With
QLatin1String("abcd")
*/
-class WrapStringLiteral: public QuickFixOperation
+class WrapStringLiteral: public CppQuickFixOperation
{
public:
- WrapStringLiteral()
- : stringLiteral(0), isObjCStringLiteral(false)
+ WrapStringLiteral(TextEditor::BaseTextEditor *editor)
+ : CppQuickFixOperation(editor), stringLiteral(0), isObjCStringLiteral(false)
{}
virtual QString description() const
return index;
}
- virtual void createChangeSet()
+ virtual void createChanges()
{
+ ChangeSet changes;
+
const int startPos = startOf(stringLiteral);
const QLatin1String replacement("QLatin1String(");
if (isObjCStringLiteral)
- replace(startPos, startPos + 1, replacement);
+ changes.replace(startPos, 1, replacement);
else
- insert(startPos, replacement);
+ changes.insert(startPos, replacement);
+
+ changes.insert(endOf(stringLiteral), ")");
- insert(endOf(stringLiteral), ")");
+ cppRefactoringChanges()->changeFile(fileName(), changes);
}
private:
bool isObjCStringLiteral;
};
-class CStringToNSString: public QuickFixOperation
+class CStringToNSString: public CppQuickFixOperation
{
public:
- CStringToNSString()
- : stringLiteral(0), qlatin1Call(0)
+ CStringToNSString(TextEditor::BaseTextEditor *editor)
+ : CppQuickFixOperation(editor), stringLiteral(0), qlatin1Call(0)
{}
virtual QString description() const
return index;
}
- virtual void createChangeSet()
+ virtual void createChanges()
{
+ ChangeSet changes;
+
if (qlatin1Call) {
- replace(startOf(qlatin1Call), startOf(stringLiteral), QLatin1String("@"));
- remove(endOf(stringLiteral), endOf(qlatin1Call));
+ changes.replace(startOf(qlatin1Call),
+ startOf(stringLiteral) - startOf(qlatin1Call),
+ QLatin1String("@"));
+ changes.remove(endOf(stringLiteral),
+ endOf(qlatin1Call) - endOf(stringLiteral));
} else {
- insert(startOf(stringLiteral), "@");
+ changes.insert(startOf(stringLiteral), "@");
}
+
+ cppRefactoringChanges()->changeFile(fileName(), changes);
}
private:
PostfixExpressionAST *qlatin1Call;
};
-/*
- Replace
- a + b
- With
- a % b
- If a and b are of string type.
-*/
-class UseFastStringConcatenation: public QuickFixOperation
-{
-public:
- UseFastStringConcatenation()
- {}
-
- virtual QString description() const
- {
- return QApplication::translate("CppTools::QuickFix", "Use Fast String Concatenation with %");
- }
-
- virtual int match(const QList<AST *> &path)
- {
- if (path.isEmpty())
- return -1;
-
- // need to search 'up' too
- int index = path.size() - 1;
- if (BinaryExpressionAST *binary = asPlusNode(path[index])) {
- while (0 != (binary = asPlusNode(binary->left_expression)))
- _binaryExpressions.prepend(binary);
- }
-
- // search 'down'
- for (index = path.size() - 1; index != -1; --index) {
- AST *node = path.at(index);
- if (BinaryExpressionAST *binary = asPlusNode(node)) {
- _binaryExpressions.append(binary);
- } else if (! _binaryExpressions.isEmpty()) {
- break;
- }
- }
-
- if (_binaryExpressions.isEmpty())
- return -1;
-
- // verify types of arguments
- BinaryExpressionAST *prevBinary = 0;
- foreach (BinaryExpressionAST *binary, _binaryExpressions) {
- if (binary->left_expression != prevBinary) {
- if (!hasCorrectType(binary->left_expression))
- return -1;
- }
- if (binary->right_expression != prevBinary) {
- if (!hasCorrectType(binary->right_expression))
- return -1;
- }
- prevBinary = binary;
- }
-
- return index + _binaryExpressions.size();
- }
-
- virtual void createChangeSet()
- {
- // replace + -> %
- foreach (BinaryExpressionAST *binary, _binaryExpressions)
- replace(binary->binary_op_token, "%");
-
- // wrap literals in QLatin1Literal
- foreach (StringLiteralAST *literal, _stringLiterals) {
- insert(startOf(literal), "QLatin1Literal(");
- insert(endOf(literal), ")");
- }
-
- // replace QLatin1String/QString/QByteArray(literal) -> QLatin1Literal(literal)
- foreach (PostfixExpressionAST *postfix, _incorrectlyWrappedLiterals) {
- replace(postfix->base_expression, "QLatin1Literal");
- }
- }
-
- BinaryExpressionAST *asPlusNode(AST *ast)
- {
- BinaryExpressionAST *binary = ast->asBinaryExpression();
- if (binary && tokenAt(binary->binary_op_token).kind() == T_PLUS)
- return binary;
- return 0;
- }
-
- bool hasCorrectType(ExpressionAST *ast)
- {
- if (StringLiteralAST *literal = ast->asStringLiteral()) {
- _stringLiterals += literal;
- return true;
- }
-
- if (PostfixExpressionAST *postfix = ast->asPostfixExpression()) {
- if (postfix->base_expression && postfix->postfix_expression_list
- && postfix->postfix_expression_list->value
- && !postfix->postfix_expression_list->next)
- {
- NameAST *name = postfix->base_expression->asName();
- CallAST *call = postfix->postfix_expression_list->value->asCall();
- if (name && call) {
- QByteArray nameStr(name->name->identifier()->chars());
- if ((nameStr == "QLatin1String"
- || nameStr == "QString"
- || nameStr == "QByteArray")
- && call->expression_list
- && call->expression_list->value
- && call->expression_list->value->asStringLiteral()
- && !call->expression_list->next)
- {
- _incorrectlyWrappedLiterals += postfix;
- return true;
- }
- }
- }
- }
-
- const QList<LookupItem> &lookup = typeOf(ast);
- if (lookup.isEmpty())
- return false;
- return isQtStringType(lookup[0].type());
- }
-
- bool isBuiltinStringType(FullySpecifiedType type)
- {
- // char*
- if (PointerType *ptrTy = type->asPointerType())
- if (IntegerType *intTy = ptrTy->elementType()->asIntegerType())
- if (intTy->kind() == IntegerType::Char)
- return true;
- return false;
- }
-
- bool isQtStringType(FullySpecifiedType type)
- {
- if (NamedType *nameTy = type->asNamedType()) {
- if (!nameTy->name() || !nameTy->name()->identifier())
- return false;
-
- QByteArray name(nameTy->name()->identifier()->chars());
- if (name == "QString"
- || name == "QByteArray"
- || name == "QLatin1String"
- || name == "QLatin1Literal"
- || name == "QStringRef"
- || name == "QChar"
- )
- return true;
- }
-
- return false;
- }
-
-private:
- QList<BinaryExpressionAST *> _binaryExpressions;
- QList<StringLiteralAST *> _stringLiterals;
- QList<PostfixExpressionAST *> _incorrectlyWrappedLiterals;
-};
-
} // end of anonymous namespace
-QuickFixOperation::QuickFixOperation()
- : _editor(0), _topLevelNode(0)
-{ }
-
-QuickFixOperation::~QuickFixOperation()
+CppQuickFixOperation::CppQuickFixOperation(TextEditor::BaseTextEditor *editor)
+ : TextEditor::QuickFixOperation(editor)
+ , _refactoringChanges(0)
+ , _topLevelNode(0)
{ }
-CPlusPlus::AST *QuickFixOperation::topLevelNode() const
-{ return _topLevelNode; }
-
-void QuickFixOperation::setTopLevelNode(CPlusPlus::AST *topLevelNode)
-{ _topLevelNode = topLevelNode; }
-
-const Utils::ChangeSet &QuickFixOperation::changeSet() const
-{ return _changeSet; }
-
-Document::Ptr QuickFixOperation::document() const
-{ return _document; }
-
-void QuickFixOperation::setDocument(CPlusPlus::Document::Ptr document)
-{ _document = document; }
-
-Snapshot QuickFixOperation::snapshot() const
-{ return _snapshot; }
+CppQuickFixOperation::~CppQuickFixOperation()
+{
+ if (_refactoringChanges)
+ delete _refactoringChanges;
+}
-void QuickFixOperation::setSnapshot(const CPlusPlus::Snapshot &snapshot)
+int CppQuickFixOperation::match(TextEditor::QuickFixState *state)
{
- _snapshot = snapshot;
+ CppQuickFixState *s = static_cast<CppQuickFixState *>(state);
+ _document = s->info.doc;
+ if (_refactoringChanges)
+ delete _refactoringChanges;
+ CPPEditor *cppEditor = qobject_cast<CPPEditor*>(editor());
+ _refactoringChanges = new CppTools::CppRefactoringChanges(s->info.snapshot, cppEditor->modelManager());
+ return match(s->path);
}
-CPPEditor *QuickFixOperation::editor() const
-{ return _editor; }
+QString CppQuickFixOperation::fileName() const
+{ return document()->fileName(); }
-void QuickFixOperation::setEditor(CPPEditor *editor)
-{ _editor = editor; }
+void CppQuickFixOperation::apply()
+{
+ cppRefactoringChanges()->apply();
+}
-QTextCursor QuickFixOperation::textCursor() const
-{ return _textCursor; }
+CppTools::CppRefactoringChanges *CppQuickFixOperation::cppRefactoringChanges() const
+{ return _refactoringChanges; }
-void QuickFixOperation::setTextCursor(const QTextCursor &cursor)
-{ _textCursor = cursor; }
+TextEditor::RefactoringChanges *CppQuickFixOperation::refactoringChanges() const
+{ return cppRefactoringChanges(); }
-int QuickFixOperation::selectionStart() const
-{ return _textCursor.selectionStart(); }
+Document::Ptr CppQuickFixOperation::document() const
+{ return _document; }
-int QuickFixOperation::selectionEnd() const
-{ return _textCursor.selectionEnd(); }
+const Snapshot &CppQuickFixOperation::snapshot() const
+{
+ return _refactoringChanges->snapshot();
+}
-const CPlusPlus::Token &QuickFixOperation::tokenAt(unsigned index) const
+const CPlusPlus::Token &CppQuickFixOperation::tokenAt(unsigned index) const
{ return _document->translationUnit()->tokenAt(index); }
-int QuickFixOperation::startOf(unsigned index) const
+int CppQuickFixOperation::startOf(unsigned index) const
{
unsigned line, column;
_document->translationUnit()->getPosition(tokenAt(index).begin(), &line, &column);
- return _textCursor.document()->findBlockByNumber(line - 1).position() + column - 1;
+ return editor()->document()->findBlockByNumber(line - 1).position() + column - 1;
}
-int QuickFixOperation::startOf(const CPlusPlus::AST *ast) const
+int CppQuickFixOperation::startOf(const CPlusPlus::AST *ast) const
{
return startOf(ast->firstToken());
}
-int QuickFixOperation::endOf(unsigned index) const
+int CppQuickFixOperation::endOf(unsigned index) const
{
unsigned line, column;
_document->translationUnit()->getPosition(tokenAt(index).end(), &line, &column);
- return _textCursor.document()->findBlockByNumber(line - 1).position() + column - 1;
+ return editor()->document()->findBlockByNumber(line - 1).position() + column - 1;
}
-int QuickFixOperation::endOf(const CPlusPlus::AST *ast) const
+int CppQuickFixOperation::endOf(const CPlusPlus::AST *ast) const
{
- return endOf(ast->lastToken() - 1);
+ if (unsigned end = ast->lastToken())
+ return endOf(end - 1);
+ else
+ return 0;
}
-void QuickFixOperation::startAndEndOf(unsigned index, int *start, int *end) const
+void CppQuickFixOperation::startAndEndOf(unsigned index, int *start, int *end) const
{
unsigned line, column;
CPlusPlus::Token token(tokenAt(index));
_document->translationUnit()->getPosition(token.begin(), &line, &column);
- *start = _textCursor.document()->findBlockByNumber(line - 1).position() + column - 1;
+ *start = editor()->document()->findBlockByNumber(line - 1).position() + column - 1;
*end = *start + token.length();
}
-bool QuickFixOperation::isCursorOn(unsigned tokenIndex) const
+bool CppQuickFixOperation::isCursorOn(unsigned tokenIndex) const
{
QTextCursor tc = textCursor();
int cursorBegin = tc.selectionStart();
return false;
}
-bool QuickFixOperation::isCursorOn(const CPlusPlus::AST *ast) const
+bool CppQuickFixOperation::isCursorOn(const CPlusPlus::AST *ast) const
{
QTextCursor tc = textCursor();
int cursorBegin = tc.selectionStart();
return false;
}
-QuickFixOperation::Range QuickFixOperation::createRange(AST *ast) const
-{
- QTextCursor tc = _textCursor;
- Range r(tc);
- r.begin.setPosition(startOf(ast));
- r.end.setPosition(endOf(ast));
- return r;
-}
-
-void QuickFixOperation::reindent(const Range &range)
+void CppQuickFixOperation::move(ChangeSet *changeSet, unsigned tokenIndex,
+ int to)
{
- QTextCursor tc = range.begin;
- tc.setPosition(range.end.position(), QTextCursor::KeepAnchor);
- _editor->indentInsertedText(tc);
-}
+ Q_ASSERT(changeSet);
-void QuickFixOperation::move(int start, int end, int to)
-{
- _changeSet.move(start, end-start, to);
-}
-
-void QuickFixOperation::move(unsigned tokenIndex, int to)
-{
int start, end;
startAndEndOf(tokenIndex, &start, &end);
- move(start, end, to);
+ changeSet->move(start, end - start, to);
}
-void QuickFixOperation::move(const CPlusPlus::AST *ast, int to)
+void CppQuickFixOperation::move(ChangeSet *changeSet, const CPlusPlus::AST *ast,
+ int to)
{
- move(startOf(ast), endOf(ast), to);
-}
+ Q_ASSERT(changeSet);
-void QuickFixOperation::replace(int start, int end, const QString &replacement)
-{
- _changeSet.replace(start, end-start, replacement);
+ const int start = startOf(ast);
+ changeSet->move(start, endOf(ast) - start, to);
}
-void QuickFixOperation::replace(unsigned tokenIndex, const QString &replacement)
+void CppQuickFixOperation::replace(ChangeSet *changeSet, unsigned tokenIndex,
+ const QString &replacement)
{
+ Q_ASSERT(changeSet);
+
int start, end;
startAndEndOf(tokenIndex, &start, &end);
- replace(start, end, replacement);
+ changeSet->replace(start, end - start, replacement);
}
-void QuickFixOperation::replace(const CPlusPlus::AST *ast, const QString &replacement)
+void CppQuickFixOperation::replace(ChangeSet *changeSet,
+ const CPlusPlus::AST *ast,
+ const QString &replacement)
{
- replace(startOf(ast), endOf(ast), replacement);
-}
+ Q_ASSERT(changeSet);
-void QuickFixOperation::insert(int at, const QString &text)
-{
- _changeSet.insert(at, text);
+ const int start = startOf(ast);
+ changeSet->replace(start, endOf(ast) - start, replacement);
}
-void QuickFixOperation::remove(int start, int end)
+void CppQuickFixOperation::remove(ChangeSet *changeSet, unsigned tokenIndex)
{
- _changeSet.remove(start, end-start);
-}
+ Q_ASSERT(changeSet);
-void QuickFixOperation::remove(unsigned tokenIndex)
-{
int start, end;
startAndEndOf(tokenIndex, &start, &end);
- remove(start, end);
+ changeSet->remove(start, end - start);
}
-void QuickFixOperation::remove(const CPlusPlus::AST *ast)
+void CppQuickFixOperation::remove(ChangeSet *changeSet, const CPlusPlus::AST *ast)
{
- remove(startOf(ast), endOf(ast));
-}
+ Q_ASSERT(changeSet);
-void QuickFixOperation::flip(int start1, int end1, int start2, int end2)
-{
- _changeSet.flip(start1, end1-start1, start2, end2-start2);
+ const int start = startOf(ast);
+ changeSet->remove(start, endOf(ast) - start);
}
-void QuickFixOperation::flip(const CPlusPlus::AST *ast1, const CPlusPlus::AST *ast2)
+void CppQuickFixOperation::flip(ChangeSet *changeSet,
+ const CPlusPlus::AST *ast1,
+ const CPlusPlus::AST *ast2)
{
- flip(startOf(ast1), endOf(ast1), startOf(ast2), endOf(ast2));
-}
+ Q_ASSERT(changeSet);
-void QuickFixOperation::copy(int start, int end, int to)
-{
- _changeSet.copy(start, end-start, to);
+ const int start1 = startOf(ast1);
+ const int start2 = startOf(ast2);
+ changeSet->flip(start1, endOf(ast1) - start1,
+ start2, endOf(ast2) - start2);
}
-void QuickFixOperation::copy(unsigned tokenIndex, int to)
+void CppQuickFixOperation::copy(ChangeSet *changeSet, unsigned tokenIndex,
+ int to)
{
+ Q_ASSERT(changeSet);
+
int start, end;
startAndEndOf(tokenIndex, &start, &end);
- copy(start, end, to);
+ changeSet->copy(start, end - start, to);
}
-void QuickFixOperation::copy(const CPlusPlus::AST *ast, int to)
+void CppQuickFixOperation::copy(ChangeSet *changeSet, const CPlusPlus::AST *ast,
+ int to)
{
- copy(startOf(ast), endOf(ast), to);
-}
+ Q_ASSERT(changeSet);
-QString QuickFixOperation::textOf(int firstOffset, int lastOffset) const
-{
- QTextCursor tc = _textCursor;
- tc.setPosition(firstOffset);
- tc.setPosition(lastOffset, QTextCursor::KeepAnchor);
- return tc.selectedText();
+ const int start = startOf(ast);
+ changeSet->copy(start, endOf(ast) - start, to);
}
-QString QuickFixOperation::textOf(const AST *ast) const
+QString CppQuickFixOperation::textOf(const AST *ast) const
{
return textOf(startOf(ast), endOf(ast));
}
-QChar QuickFixOperation::charAt(int offset) const
+CppQuickFixCollector::CppQuickFixCollector()
{
- return textOf(offset, offset + 1).at(0);
}
-void QuickFixOperation::apply()
+CppQuickFixCollector::~CppQuickFixCollector()
{
- Range range;
-
- if (_topLevelNode)
- range = createRange(_topLevelNode);
-
- _textCursor.beginEditBlock();
-
- _changeSet.apply(&_textCursor);
-
- if (_topLevelNode)
- reindent(range);
-
- _textCursor.endEditBlock();
}
-/**
- * Returns a list of possible fully specified types associated with the
- * given expression.
- *
- * NOTE: The fully specified types only stay valid until the next call to typeOf.
- */
-const QList<LookupItem> QuickFixOperation::typeOf(CPlusPlus::ExpressionAST *ast)
+bool CppQuickFixCollector::supportsEditor(TextEditor::ITextEditable *editor)
{
- unsigned line, column;
- document()->translationUnit()->getTokenStartPosition(ast->firstToken(), &line, &column);
- Symbol *lastVisibleSymbol = document()->findSymbolAt(line, column);
-
- _lookupContext = LookupContext(lastVisibleSymbol, document(), document(), snapshot());
-
- ResolveExpression resolveExpression(_lookupContext);
- return resolveExpression(ast);
+ return CppTools::CppModelManagerInterface::instance()->isCppEditor(editor);
}
-CPPQuickFixCollector::CPPQuickFixCollector()
- : _modelManager(CppTools::CppModelManagerInterface::instance()), _editable(0), _editor(0)
-{ }
-
-CPPQuickFixCollector::~CPPQuickFixCollector()
-{ }
-
-TextEditor::ITextEditable *CPPQuickFixCollector::editor() const
-{ return _editable; }
-
-int CPPQuickFixCollector::startPosition() const
-{ return _editable->position(); }
-
-bool CPPQuickFixCollector::supportsEditor(TextEditor::ITextEditable *editor)
-{ return qobject_cast<CPPEditorEditable *>(editor) != 0; }
-
-bool CPPQuickFixCollector::triggersCompletion(TextEditor::ITextEditable *)
-{ return false; }
-
-int CPPQuickFixCollector::startCompletion(TextEditor::ITextEditable *editable)
+TextEditor::QuickFixState *CppQuickFixCollector::initializeCompletion(TextEditor::ITextEditable *editable)
{
- Q_ASSERT(editable != 0);
-
- _editable = editable;
- _editor = qobject_cast<CPPEditor *>(editable->widget());
- Q_ASSERT(_editor != 0);
+ if (CPPEditor *editor = qobject_cast<CPPEditor *>(editable->widget())) {
+ const SemanticInfo info = editor->semanticInfo();
- const SemanticInfo info = _editor->semanticInfo();
-
- if (info.revision != _editor->editorRevision()) {
- // outdated
- qWarning() << "TODO: outdated semantic info, force a reparse.";
- return -1;
- }
-
- if (info.doc) {
- ASTPath astPath(info.doc);
-
- const QList<AST *> path = astPath(_editor->textCursor());
- if (path.isEmpty())
- return -1;
-
- QSharedPointer<RewriteLogicalAndOp> rewriteLogicalAndOp(new RewriteLogicalAndOp());
- QSharedPointer<SplitIfStatementOp> splitIfStatementOp(new SplitIfStatementOp());
- QSharedPointer<MoveDeclarationOutOfIfOp> moveDeclarationOutOfIfOp(new MoveDeclarationOutOfIfOp());
- QSharedPointer<MoveDeclarationOutOfWhileOp> moveDeclarationOutOfWhileOp(new MoveDeclarationOutOfWhileOp());
- QSharedPointer<SplitSimpleDeclarationOp> splitSimpleDeclarationOp(new SplitSimpleDeclarationOp());
- QSharedPointer<AddBracesToIfOp> addBracesToIfOp(new AddBracesToIfOp());
- QSharedPointer<UseInverseOp> useInverseOp(new UseInverseOp());
- QSharedPointer<FlipBinaryOp> flipBinaryOp(new FlipBinaryOp());
- QSharedPointer<WrapStringLiteral> wrapStringLiteral(new WrapStringLiteral());
- QSharedPointer<CStringToNSString> wrapCString(new CStringToNSString());
- QSharedPointer<UseFastStringConcatenation> useFastStringConcat(new UseFastStringConcatenation());
-
- QList<QuickFixOperationPtr> candidates;
- candidates.append(rewriteLogicalAndOp);
- candidates.append(splitIfStatementOp);
- candidates.append(moveDeclarationOutOfIfOp);
- candidates.append(moveDeclarationOutOfWhileOp);
- candidates.append(splitSimpleDeclarationOp);
- candidates.append(addBracesToIfOp);
- candidates.append(useInverseOp);
- candidates.append(flipBinaryOp);
- candidates.append(wrapStringLiteral);
- if (_editor->mimeType() == CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)
- candidates.append(wrapCString);
- candidates.append(useFastStringConcat);
-
- QMap<int, QList<QuickFixOperationPtr> > matchedOps;
-
- foreach (QuickFixOperationPtr op, candidates) {
- op->setSnapshot(info.snapshot);
- op->setDocument(info.doc);
- op->setEditor(_editor);
- op->setTextCursor(_editor->textCursor());
- int priority = op->match(path);
- if (priority != -1)
- matchedOps[priority].append(op);
+ if (info.revision != editor->editorRevision()) {
+ // outdated
+ qWarning() << "TODO: outdated semantic info, force a reparse.";
+ return 0;
}
- QMapIterator<int, QList<QuickFixOperationPtr> > it(matchedOps);
- it.toBack();
- if (it.hasPrevious()) {
- it.previous();
+ if (info.doc) {
+ ASTPath astPath(info.doc);
- _quickFixes = it.value();
+ const QList<AST *> path = astPath(editor->textCursor());
+ if (! path.isEmpty()) {
+ CppQuickFixState *state = new CppQuickFixState;
+ state->path = path;
+ state->info = info;
+ return state;
+ }
}
-
- if (! _quickFixes.isEmpty())
- return editable->position();
}
- return -1;
-}
-
-void CPPQuickFixCollector::completions(QList<TextEditor::CompletionItem> *quickFixItems)
-{
- for (int i = 0; i < _quickFixes.size(); ++i) {
- QuickFixOperationPtr op = _quickFixes.at(i);
-
- TextEditor::CompletionItem item(this);
- item.text = op->description();
- item.data = QVariant::fromValue(i);
- quickFixItems->append(item);
- }
-}
-
-void CPPQuickFixCollector::complete(const TextEditor::CompletionItem &item)
-{
- const int index = item.data.toInt();
-
- if (index < _quickFixes.size()) {
- QuickFixOperationPtr quickFix = _quickFixes.at(index);
- perform(quickFix);
- }
-}
-
-void CPPQuickFixCollector::perform(QuickFixOperationPtr op)
-{
- op->setTextCursor(_editor->textCursor());
- op->createChangeSet();
- op->apply();
+ return 0;
}
-void CPPQuickFixCollector::cleanup()
+QList<TextEditor::QuickFixOperation::Ptr> CppQuickFixCollector::quickFixOperations(TextEditor::BaseTextEditor *editor) const
{
- _quickFixes.clear();
+ QSharedPointer<RewriteLogicalAndOp> rewriteLogicalAndOp(new RewriteLogicalAndOp(editor));
+ QSharedPointer<SplitIfStatementOp> splitIfStatementOp(new SplitIfStatementOp(editor));
+ QSharedPointer<MoveDeclarationOutOfIfOp> moveDeclarationOutOfIfOp(new MoveDeclarationOutOfIfOp(editor));
+ QSharedPointer<MoveDeclarationOutOfWhileOp> moveDeclarationOutOfWhileOp(new MoveDeclarationOutOfWhileOp(editor));
+ QSharedPointer<SplitSimpleDeclarationOp> splitSimpleDeclarationOp(new SplitSimpleDeclarationOp(editor));
+ QSharedPointer<AddBracesToIfOp> addBracesToIfOp(new AddBracesToIfOp(editor));
+ QSharedPointer<UseInverseOp> useInverseOp(new UseInverseOp(editor));
+ QSharedPointer<FlipBinaryOp> flipBinaryOp(new FlipBinaryOp(editor));
+ QSharedPointer<WrapStringLiteral> wrapStringLiteral(new WrapStringLiteral(editor));
+ QSharedPointer<CStringToNSString> wrapCString(new CStringToNSString(editor));
+
+ QList<TextEditor::QuickFixOperation::Ptr> quickFixOperations;
+ quickFixOperations.append(rewriteLogicalAndOp);
+ quickFixOperations.append(splitIfStatementOp);
+ quickFixOperations.append(moveDeclarationOutOfIfOp);
+ quickFixOperations.append(moveDeclarationOutOfWhileOp);
+ quickFixOperations.append(splitSimpleDeclarationOp);
+ quickFixOperations.append(addBracesToIfOp);
+ quickFixOperations.append(useInverseOp);
+ quickFixOperations.append(flipBinaryOp);
+ quickFixOperations.append(wrapStringLiteral);
+
+ if (editor->mimeType() == CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)
+ quickFixOperations.append(wrapCString);
+
+ return quickFixOperations;
}
#define CPPQUICKFIX_H
#include <texteditor/icompletioncollector.h>
+#include <texteditor/quickfix.h>
#include <cplusplus/CppDocument.h>
-#include <cplusplus/LookupContext.h>
#include <ASTfwd.h>
#include <utils/changeset.h>
namespace CppTools {
class CppModelManagerInterface;
+ class CppRefactoringChanges;
} // end of namespace CppTools
namespace CppEditor {
namespace Internal {
-class CPPEditor;
-class QuickFixOperation;
-typedef QSharedPointer<QuickFixOperation> QuickFixOperationPtr;
-
-class QuickFixOperation
+class CppQuickFixOperation: public TextEditor::QuickFixOperation
{
- Q_DISABLE_COPY(QuickFixOperation)
+ Q_DISABLE_COPY(CppQuickFixOperation)
public:
- QuickFixOperation();
- virtual ~QuickFixOperation();
+ CppQuickFixOperation(TextEditor::BaseTextEditor *editor);
+ virtual ~CppQuickFixOperation();
- virtual QString description() const = 0;
virtual int match(const QList<CPlusPlus::AST *> &path) = 0;
- virtual void createChangeSet() = 0;
-
- void apply();
CPlusPlus::Document::Ptr document() const;
- void setDocument(CPlusPlus::Document::Ptr document);
-
- CPlusPlus::Snapshot snapshot() const;
- void setSnapshot(const CPlusPlus::Snapshot &snapshot);
-
- CPPEditor *editor() const;
- void setEditor(CPPEditor *editor);
+ const CPlusPlus::Snapshot &snapshot() const;
- QTextCursor textCursor() const;
- void setTextCursor(const QTextCursor &cursor);
-
- int selectionStart() const;
- int selectionEnd() const;
-
- const Utils::ChangeSet &changeSet() const;
+ virtual int match(TextEditor::QuickFixState *state);
protected:
- CPlusPlus::AST *topLevelNode() const;
- void setTopLevelNode(CPlusPlus::AST *topLevelNode);
+ QString fileName() const;
+
+ virtual void apply();
+ virtual CppTools::CppRefactoringChanges *cppRefactoringChanges() const;
+ virtual TextEditor::RefactoringChanges *refactoringChanges() const;
const CPlusPlus::Token &tokenAt(unsigned index) const;
bool isCursorOn(unsigned tokenIndex) const;
bool isCursorOn(const CPlusPlus::AST *ast) const;
- void move(int start, int end, int to);
- void move(unsigned tokenIndex, int to);
- void move(const CPlusPlus::AST *ast, int to);
- void replace(int start, int end, const QString &replacement);
- void replace(unsigned tokenIndex, const QString &replacement);
- void replace(const CPlusPlus::AST *ast, const QString &replacement);
- void insert(int at, const QString &text);
- void remove(int start, int end);
- void remove(unsigned tokenIndex);
- void remove(const CPlusPlus::AST *ast);
- void flip(int start1, int end1, int start2, int end2);
- void flip(const CPlusPlus::AST *ast1, const CPlusPlus::AST *ast2);
- void copy(int start, int end, int to);
- void copy(unsigned tokenIndex, int to);
- void copy(const CPlusPlus::AST *ast, int to);
-
- QString textOf(int firstOffset, int lastOffset) const;
- QString textOf(const CPlusPlus::AST *ast) const;
- QChar charAt(int offset) const;
-
- struct Range {
- Range() {}
- Range(const QTextCursor &tc): begin(tc), end(tc) {}
-
- QTextCursor begin;
- QTextCursor end;
- };
+ using TextEditor::QuickFixOperation::textOf;
+ using TextEditor::QuickFixOperation::charAt;
+
+ void move(Utils::ChangeSet *changeSet, unsigned tokenIndex, int to);
+ void move(Utils::ChangeSet *changeSet, const CPlusPlus::AST *ast, int to);
+ void replace(Utils::ChangeSet *changeSet, unsigned tokenIndex,
+ const QString &replacement);
+ void replace(Utils::ChangeSet *changeSet, const CPlusPlus::AST *ast,
+ const QString &replacement);
+ void remove(Utils::ChangeSet *changeSet, unsigned tokenIndex);
+ void remove(Utils::ChangeSet *changeSet, const CPlusPlus::AST *ast);
+ void flip(Utils::ChangeSet *changeSet, const CPlusPlus::AST *ast1,
+ const CPlusPlus::AST *ast2);
+ void copy(Utils::ChangeSet *changeSet, unsigned tokenIndex, int to);
+ void copy(Utils::ChangeSet *changeSet, const CPlusPlus::AST *ast, int to);
- Range createRange(CPlusPlus::AST *ast) const; // ### rename me
- void reindent(const Range &range);
-
- const QList<CPlusPlus::LookupItem> typeOf(CPlusPlus::ExpressionAST *ast);
+ QString textOf(const CPlusPlus::AST *ast) const;
private:
+ CppTools::CppRefactoringChanges *_refactoringChanges;
CPlusPlus::Document::Ptr _document;
- CPlusPlus::Snapshot _snapshot;
- QTextCursor _textCursor;
- Utils::ChangeSet _changeSet;
- CPPEditor *_editor;
CPlusPlus::AST *_topLevelNode;
- CPlusPlus::LookupContext _lookupContext;
};
-class CPPQuickFixCollector: public TextEditor::IQuickFixCollector
+class CppQuickFixCollector: public TextEditor::QuickFixCollector
{
Q_OBJECT
public:
- CPPQuickFixCollector();
- virtual ~CPPQuickFixCollector();
+ CppQuickFixCollector();
+ virtual ~CppQuickFixCollector();
- QList<QuickFixOperationPtr> quickFixes() const { return _quickFixes; }
-
- virtual TextEditor::ITextEditable *editor() const;
- virtual int startPosition() const;
virtual bool supportsEditor(TextEditor::ITextEditable *editor);
- virtual bool triggersCompletion(TextEditor::ITextEditable *editor);
- virtual int startCompletion(TextEditor::ITextEditable *editor);
- virtual void completions(QList<TextEditor::CompletionItem> *completions);
- virtual void complete(const TextEditor::CompletionItem &item);
- virtual void cleanup();
-
-public Q_SLOTS:
- void perform(QuickFixOperationPtr op);
-
-private:
- CppTools::CppModelManagerInterface *_modelManager;
- TextEditor::ITextEditable *_editable;
- CPPEditor *_editor;
- QList<QuickFixOperationPtr> _quickFixes;
+ virtual TextEditor::QuickFixState *initializeCompletion(TextEditor::ITextEditable *editable);
+ virtual QList<TextEditor::QuickFixOperation::Ptr> quickFixOperations(TextEditor::BaseTextEditor *editor) const;
};
} // end of namespace Internal
-<plugin name="CppTools" version="2.0.80" compatVersion="2.0.80">
+<plugin name="CppTools" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Tools for analyzing C/C++ code.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
- <dependency name="Locator" version="2.0.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
+ <dependency name="Locator" version="2.1.80"/>
</dependencyList>
</plugin>
const CPlusPlus::Document::Ptr document = snapshot.document(fileName);
if (!document)
return QString();
- if (const CPlusPlus::Symbol *symbol = document->findSymbolAt(line, column))
+ if (const CPlusPlus::Symbol *symbol = document->lastVisibleSymbolAt(line, column))
if (const CPlusPlus::Scope *scope = symbol->scope())
if (const CPlusPlus::Scope *functionScope = scope->enclosingFunctionScope())
if (const CPlusPlus::Symbol *function = functionScope->owner()) {
#include <TranslationUnit.h>
#include <cplusplus/ResolveExpression.h>
-#include <cplusplus/LookupContext.h>
#include <cplusplus/MatchingText.h>
#include <cplusplus/Overview.h>
#include <cplusplus/ExpressionUnderCursor.h>
#include <cplusplus/BackwardsScanner.h>
-#include <cplusplus/TokenUnderCursor.h>
+#include <cplusplus/LookupContext.h>
#include <coreplugin/icore.h>
#include <coreplugin/mimedatabase.h>
#include <utils/faketooltip.h>
#include <utils/qtcassert.h>
-#include <QtCore/QDebug>
#include <QtCore/QMap>
#include <QtCore/QFile>
#include <QtGui/QAction>
#include <QtGui/QToolButton>
#include <QtGui/QVBoxLayout>
+namespace {
+ const bool debug = ! qgetenv("CPLUSPLUS_DEBUG").isEmpty();
+}
+
using namespace CPlusPlus;
namespace CppTools {
/*
Searches backwards for an access operator.
*/
-static int startOfOperator(TextEditor::ITextEditable *editor,
+static int startOfOperator(TokenCache *tokenCache,
+ TextEditor::ITextEditable *editor,
int pos, unsigned *kind,
bool wantFunctionCall)
{
completionKind = T_SLASH;
--start;
break;
+ case '#':
+ completionKind = T_POUND;
+ --start;
+ break;
}
if (start == pos)
}
if (completionKind == T_COMMA) {
- ExpressionUnderCursor expressionUnderCursor;
+ ExpressionUnderCursor expressionUnderCursor(tokenCache);
if (expressionUnderCursor.startOfFunctionCall(tc) == -1) {
completionKind = T_EOF_SYMBOL;
start = pos;
}
}
- static CPlusPlus::TokenUnderCursor tokenUnderCursor;
- const SimpleToken tk = tokenUnderCursor(tc);
+ const SimpleToken tk = tokenCache->tokenUnderCursor(tc);
if (completionKind == T_DOXY_COMMENT && !(tk.is(T_DOXY_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))) {
completionKind = T_EOF_SYMBOL;
start = pos;
}
else if (completionKind == T_LPAREN) {
- const QList<SimpleToken> &tokens = tokenUnderCursor.tokens();
+ const QList<SimpleToken> &tokens = tokenCache->tokensForBlock(tc.block());
int i = 0;
for (; i < tokens.size(); ++i) {
const SimpleToken &token = tokens.at(i);
// Check for include preprocessor directive
else if (completionKind == T_STRING_LITERAL || completionKind == T_ANGLE_STRING_LITERAL || completionKind == T_SLASH) {
bool include = false;
- const QList<SimpleToken> &tokens = tokenUnderCursor.tokens();
+ const QList<SimpleToken> &tokens = tokenCache->tokensForBlock(tc.block());
if (tokens.size() >= 3) {
if (tokens.at(0).is(T_POUND) && tokens.at(1).is(T_IDENTIFIER) && (tokens.at(2).is(T_STRING_LITERAL) ||
tokens.at(2).is(T_ANGLE_STRING_LITERAL))) {
- QStringRef directive = tokens.at(1).text();
+ QString directive = tokenCache->text(tc.block(), 1);
if (directive == QLatin1String("include") ||
directive == QLatin1String("include_next") ||
directive == QLatin1String("import")) {
bool CppCodeCompletion::triggersCompletion(TextEditor::ITextEditable *editor)
{
const int pos = editor->position();
- if (startOfOperator(editor, pos, /*token =*/ 0, /*want function call=*/ true) != pos) {
+ TokenCache *tokenCache = m_manager->tokenCache(editor);
+ unsigned token = T_EOF_SYMBOL;
+
+ if (startOfOperator(tokenCache, editor, pos, &token, /*want function call=*/ true) != pos) {
+ if (token == T_POUND) {
+ if (TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget())) {
+ QTextCursor tc(edit->document());
+ tc.setPosition(pos);
+ return tc.columnNumber() == 1;
+ }
+
+ return false;
+ }
+
return true;
}
int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
{
+ int index = startCompletionHelper(editor);
+ if (index != -1) {
+ if (m_completionOperator != T_EOF_SYMBOL)
+ qSort(m_completions.begin(), m_completions.end(), completionItemLessThan);
+
+ // always remove duplicates
+ m_completions = removeDuplicates(m_completions);
+ }
+ return index;
+}
+
+int CppCodeCompletion::startCompletionHelper(TextEditor::ITextEditable *editor)
+{
TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget());
if (! edit)
return -1;
while (editor->characterAt(endOfOperator - 1).isSpace())
--endOfOperator;
- int endOfExpression = startOfOperator(editor, endOfOperator,
+ TokenCache *tokenCache = m_manager->tokenCache(editor);
+ int endOfExpression = startOfOperator(tokenCache, editor, endOfOperator,
&m_completionOperator,
/*want function call =*/ true);
return m_startPosition;
}
+ // Pre-processor completion
+ if (m_completionOperator == T_POUND) {
+ completePreprocessor();
+ m_startPosition = startOfName;
+ return m_startPosition;
+ }
+
// Include completion
if (m_completionOperator == T_STRING_LITERAL
|| m_completionOperator == T_ANGLE_STRING_LITERAL
return m_startPosition;
}
- ExpressionUnderCursor expressionUnderCursor;
+ ExpressionUnderCursor expressionUnderCursor(m_manager->tokenCache(editor));
QTextCursor tc(edit->document());
if (m_completionOperator == T_COMMA) {
if (! thisDocument)
return -1;
- typeOfExpression.setSnapshot(snapshot);
- Symbol *lastVisibleSymbol = thisDocument->findSymbolAt(line, column);
+ typeOfExpression.init(thisDocument, snapshot);
+
+ Scope *scope = thisDocument->scopeAt(line, column);
+ Q_ASSERT(scope != 0);
if (expression.isEmpty()) {
- if (m_completionOperator == T_EOF_SYMBOL || m_completionOperator == T_COLON_COLON)
- return globalCompletion(lastVisibleSymbol, thisDocument, snapshot);
+ if (m_completionOperator == T_EOF_SYMBOL || m_completionOperator == T_COLON_COLON) {
+ (void) typeOfExpression(expression, scope);
+ globalCompletion(scope);
+ if (m_completions.isEmpty())
+ return -1;
+ return m_startPosition;
+ }
else if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
// Apply signal/slot completion on 'this'
}
}
-
- QList<LookupItem> results = typeOfExpression(expression, thisDocument, lastVisibleSymbol, TypeOfExpression::Preprocess);
- LookupContext context = typeOfExpression.lookupContext();
+ QList<LookupItem> results = typeOfExpression(expression, scope, TypeOfExpression::Preprocess);
if (results.isEmpty()) {
if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
if (! (expression.isEmpty() || expression == QLatin1String("this"))) {
expression = QLatin1String("this");
- results = typeOfExpression(expression, thisDocument, lastVisibleSymbol);
+ results = typeOfExpression(expression, scope);
}
if (results.isEmpty())
return -1;
- context = typeOfExpression.lookupContext();
-
} else if (m_completionOperator == T_LPAREN) {
// Find the expression that precedes the current name
int index = endOfExpression;
QTextCursor tc(edit->document());
tc.setPosition(index);
- ExpressionUnderCursor expressionUnderCursor;
+ TokenCache *tokenCache = m_manager->tokenCache(edit->editableInterface());
+ ExpressionUnderCursor expressionUnderCursor(tokenCache);
const QString baseExpression = expressionUnderCursor(tc);
// Resolve the type of this expression
const QList<LookupItem> results =
- typeOfExpression(baseExpression, thisDocument,
- lastVisibleSymbol,
+ typeOfExpression(baseExpression, scope,
TypeOfExpression::Preprocess);
// If it's a class, add completions for the constructors
foreach (const LookupItem &result, results) {
if (result.type()->isClassType()) {
- if (completeConstructorOrFunction(results, context, endOfExpression, true))
+ if (completeConstructorOrFunction(results, endOfExpression, true))
return m_startPosition;
break;
switch (m_completionOperator) {
case T_LPAREN:
- if (completeConstructorOrFunction(results, context, endOfExpression, false))
+ if (completeConstructorOrFunction(results, endOfExpression, false))
return m_startPosition;
break;
case T_DOT:
case T_ARROW:
- if (completeMember(results, context))
+ if (completeMember(results))
return m_startPosition;
break;
case T_COLON_COLON:
- if (completeScope(results, context))
+ if (completeScope(results))
return m_startPosition;
break;
case T_SIGNAL:
- if (completeSignal(results, context))
+ if (completeSignal(results))
return m_startPosition;
break;
case T_SLOT:
- if (completeSlot(results, context))
+ if (completeSlot(results))
return m_startPosition;
break;
return -1;
}
-int CppCodeCompletion::globalCompletion(Symbol *lastVisibleSymbol,
- Document::Ptr thisDocument,
- const Snapshot &snapshot)
+void CppCodeCompletion::globalCompletion(Scope *currentScope)
{
- if (m_completionOperator == T_EOF_SYMBOL) {
- addKeywords();
- addMacros(thisDocument->fileName(), snapshot);
+ const LookupContext &context = typeOfExpression.context();
+
+ if (m_completionOperator == T_COLON_COLON) {
+ completeNamespace(context.globalNamespace());
+ return;
}
- Document::Ptr exprDoc = Document::create(QLatin1String("<expression>"));
- const LookupContext context(lastVisibleSymbol, exprDoc, thisDocument, snapshot);
- const QList<Scope *> scopes = context.expand(context.visibleScopes());
+ QList<ClassOrNamespace *> usingBindings;
+ ClassOrNamespace *currentBinding = 0;
- foreach (Scope *scope, scopes) {
- for (unsigned i = 0; i < scope->symbolCount(); ++i) {
- addCompletionItem(scope->symbolAt(i));
+ for (Scope *scope = currentScope; scope; scope = scope->enclosingScope()) {
+ if (scope->isBlockScope()) {
+ if (ClassOrNamespace *binding = context.lookupType(scope->owner())) {
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ Symbol *member = scope->symbolAt(i);
+ if (! member->name())
+ continue;
+ else if (UsingNamespaceDirective *u = member->asUsingNamespaceDirective()) {
+ if (ClassOrNamespace *b = binding->lookupType(u->name()))
+ usingBindings.append(b);
+ }
+ }
+ }
+ } else if (scope->isFunctionScope() || scope->isClassScope() || scope->isNamespaceScope()) {
+ currentBinding = context.lookupType(scope->owner());
+ break;
+ }
+ }
+
+ for (Scope *scope = currentScope; scope; scope = scope->enclosingScope()) {
+ if (scope->isBlockScope()) {
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ addCompletionItem(scope->symbolAt(i));
+ }
+ } else if (scope->isFunctionScope()) {
+ Scope *arguments = scope->owner()->asFunction()->arguments();
+ for (unsigned i = 0; i < arguments->symbolCount(); ++i) {
+ addCompletionItem(arguments->symbolAt(i));
+ }
+ break;
+ } else {
+ break;
+ }
+ }
+
+ for (; currentBinding; currentBinding = currentBinding->parent()) {
+ const QList<Symbol *> symbols = currentBinding->symbols();
+
+ if (! symbols.isEmpty()) {
+ if (symbols.first()->isNamespace())
+ completeNamespace(currentBinding);
+ else
+ completeClass(currentBinding);
}
}
- return m_startPosition;
+ foreach (ClassOrNamespace *b, usingBindings)
+ completeNamespace(b);
+
+ addKeywords();
+ addMacros(context.thisDocument()->fileName(), context.snapshot());
}
bool CppCodeCompletion::completeConstructorOrFunction(const QList<LookupItem> &results,
- const LookupContext &context,
int endOfExpression, bool toolTipOnly)
{
+ const LookupContext &context = typeOfExpression.context();
QList<Function *> functions;
foreach (const LookupItem &result, results) {
}
if (functions.isEmpty()) {
- ResolveExpression resolveExpression(context);
- ResolveClass resolveClass;
const Name *functionCallOp = context.control()->operatorNameId(OperatorNameId::FunctionCallOp);
foreach (const LookupItem &result, results) {
FullySpecifiedType ty = result.type().simplified();
+ Scope *scope = result.scope();
if (NamedType *namedTy = ty->asNamedType()) {
- const QList<Symbol *> classObjectCandidates = resolveClass(namedTy->name(), result, context);
-
- foreach (Symbol *classObjectCandidate, classObjectCandidates) {
- if (Class *klass = classObjectCandidate->asClass()) {
- const QList<LookupItem> overloads =
- resolveExpression.resolveMember(functionCallOp, klass,
- namedTy->name());
+ if (ClassOrNamespace *b = context.lookupType(namedTy->name(), scope)) {
+ foreach (Symbol *overload, b->lookup(functionCallOp)) {
+ FullySpecifiedType overloadTy = overload->type().simplified();
- foreach (const LookupItem &overloadResult, overloads) {
- FullySpecifiedType overloadTy = overloadResult.type().simplified();
-
- if (Function *funTy = overloadTy->asFunctionType())
- functions.append(funTy);
- }
+ if (Function *funTy = overloadTy->asFunctionType())
+ functions.append(funTy);
}
}
}
// find a scope that encloses the current location, starting from the lastVisibileSymbol
// and moving outwards
Scope *sc = 0;
- if (context.symbol())
- sc = context.symbol()->scope();
+ if (typeOfExpression.scope())
+ sc = typeOfExpression.scope();
else if (context.thisDocument())
sc = context.thisDocument()->globalSymbols();
QTextCursor tc(edit->document());
tc.setPosition(endOfExpression);
- BackwardsScanner bs(tc);
+ TokenCache *tokenCache = m_manager->tokenCache(m_editor);
+ BackwardsScanner bs(tokenCache, tc);
const int startToken = bs.startToken();
const int lineStartToken = bs.startOfLine(startToken);
// make sure the required tokens are actually available
m_functionArgumentWidget = new FunctionArgumentWidget;
m_functionArgumentWidget->showFunctionHint(functions,
- typeOfExpression.lookupContext(),
+ typeOfExpression.context(),
m_startPosition);
}
return false;
}
-bool CppCodeCompletion::completeMember(const QList<LookupItem> &baseResults,
- const LookupContext &context)
+bool CppCodeCompletion::completeMember(const QList<LookupItem> &baseResults)
{
+ const LookupContext &context = typeOfExpression.context();
+
+// if (debug)
+// qDebug() << Q_FUNC_INFO << __LINE__;
+
if (baseResults.isEmpty())
return false;
ResolveExpression resolveExpression(context);
- ResolveClass resolveClass;
bool replacedDotOperator = false;
- const QList<LookupItem> classObjectResults =
- resolveExpression.resolveBaseExpression(baseResults,
- m_completionOperator,
- &replacedDotOperator);
-
- QList<Symbol *> classObjectCandidates;
- foreach (const LookupItem &r, classObjectResults) {
- FullySpecifiedType ty = r.type().simplified();
- if (Class *klass = ty->asClassType())
- classObjectCandidates.append(klass);
-
- else if (NamedType *namedTy = ty->asNamedType()) {
- const Name *className = namedTy->name();
- const QList<Symbol *> classes = resolveClass(className, r, context);
-
- foreach (Symbol *c, classes) {
- if (Class *klass = c->asClass())
- classObjectCandidates.append(klass);
- }
+ if (ClassOrNamespace *binding = resolveExpression.baseExpression(baseResults,
+ m_completionOperator,
+ &replacedDotOperator)) {
+// if (debug)
+// qDebug() << "cool we got a binding for the base expression";
+
+ if (replacedDotOperator && binding) {
+ // Replace . with ->
+ int length = m_editor->position() - m_startPosition + 1;
+ m_editor->setCurPos(m_startPosition - 1);
+ m_editor->replace(length, QLatin1String("->"));
+ ++m_startPosition;
}
- }
- if (replacedDotOperator && ! classObjectCandidates.isEmpty()) {
- // Replace . with ->
- int length = m_editor->position() - m_startPosition + 1;
- m_editor->setCurPos(m_startPosition - 1);
- m_editor->replace(length, QLatin1String("->"));
- ++m_startPosition;
+ if (binding)
+ completeClass(binding, /*static lookup = */ false);
+
+ return ! m_completions.isEmpty();
}
- completeClass(classObjectCandidates, context, /*static lookup = */ false);
- if (! m_completions.isEmpty())
- return true;
+// if (debug) {
+// Overview oo;
+// qDebug() << "hmm, got:" << oo(baseResults.first().type());
+// }
return false;
}
-bool CppCodeCompletion::completeScope(const QList<LookupItem> &results,
- const LookupContext &context)
+bool CppCodeCompletion::completeScope(const QList<LookupItem> &results)
{
- QList<Symbol *> classes, namespaces;
+ const LookupContext &context = typeOfExpression.context();
+ if (results.isEmpty())
+ return false;
foreach (const LookupItem &result, results) {
FullySpecifiedType ty = result.type();
+ Scope *scope = result.scope();
- if (Class *classTy = ty->asClassType())
- classes.append(classTy);
+ if (NamedType *namedTy = ty->asNamedType()) {
+ if (ClassOrNamespace *b = context.lookupType(namedTy->name(), scope)) {
+ completeClass(b);
+ break;
+ }
- else if (Namespace *namespaceTy = ty->asNamespaceType())
- namespaces.append(namespaceTy);
- }
+ } else if (Class *classTy = ty->asClassType()) {
+ if (ClassOrNamespace *b = context.lookupType(classTy)) {
+ completeClass(b);
+ break;
+ }
- if (! classes.isEmpty())
- completeClass(classes, context);
+ } else if (Namespace *nsTy = ty->asNamespaceType()) {
+ if (ClassOrNamespace *b = context.lookupType(nsTy)) {
+ completeNamespace(b);
+ break;
+ }
- else if (! namespaces.isEmpty() && m_completions.isEmpty())
- completeNamespace(namespaces, context);
+ }
+ }
return ! m_completions.isEmpty();
}
return !m_completions.isEmpty();
}
-void CppCodeCompletion::completeNamespace(const QList<Symbol *> &candidates,
- const LookupContext &context)
+QStringList CppCodeCompletion::preprocessorCompletions
+ = QStringList()
+ << QLatin1String("define")
+ << QLatin1String("error")
+ << QLatin1String("include")
+ << QLatin1String("line")
+ << QLatin1String("pragma")
+ << QLatin1String("undef")
+ << QLatin1String("if")
+ << QLatin1String("ifdef")
+ << QLatin1String("ifndef")
+ << QLatin1String("elif")
+ << QLatin1String("else")
+ << QLatin1String("endif")
+ ;
+
+void CppCodeCompletion::completePreprocessor()
{
- QList<Scope *> todo;
- QList<Scope *> visibleScopes = context.visibleScopes();
- foreach (Symbol *candidate, candidates) {
- if (Namespace *ns = candidate->asNamespace())
- context.expand(ns->members(), visibleScopes, &todo);
+ TextEditor::CompletionItem item(this);
+
+ foreach (const QString &preprocessorCompletion, preprocessorCompletions) {
+ item.text = preprocessorCompletion;
+ m_completions.append(item);
+ }
+
+ if (objcKeywordsWanted()) {
+ item.text = QLatin1String("import");
+ m_completions.append(item);
}
+}
+
+void CppCodeCompletion::completeNamespace(ClassOrNamespace *b)
+{
+ QSet<ClassOrNamespace *> bindingsVisited;
+ QList<ClassOrNamespace *> bindingsToVisit;
+ bindingsToVisit.append(b);
- foreach (Scope *scope, todo) {
- if (! (scope->isNamespaceScope() || scope->isEnumScope()))
+ while (! bindingsToVisit.isEmpty()) {
+ ClassOrNamespace *binding = bindingsToVisit.takeFirst();
+ if (! binding || bindingsVisited.contains(binding))
continue;
- addCompletionItem(scope->owner());
+ bindingsVisited.insert(binding);
+ bindingsToVisit += binding->usings();
- for (unsigned i = 0; i < scope->symbolCount(); ++i) {
- addCompletionItem(scope->symbolAt(i));
+ QList<Scope *> scopesToVisit;
+ QSet<Scope *> scopesVisited;
+
+ foreach (Symbol *bb, binding->symbols()) {
+ if (Namespace *ns = bb->asNamespace())
+ scopesToVisit.append(ns->members());
+ }
+
+ foreach (Enum *e, binding->enums()) {
+ scopesToVisit.append(e->members());
+ }
+
+ while (! scopesToVisit.isEmpty()) {
+ Scope *scope = scopesToVisit.takeFirst();
+ if (! scope || scopesVisited.contains(scope))
+ continue;
+
+ scopesVisited.insert(scope);
+
+ for (Scope::iterator it = scope->firstSymbol(); it != scope->lastSymbol(); ++it) {
+ Symbol *member = *it;
+ addCompletionItem(member);
+ }
}
}
}
-void CppCodeCompletion::completeClass(const QList<Symbol *> &candidates,
- const LookupContext &context,
- bool staticLookup)
+void CppCodeCompletion::completeClass(ClassOrNamespace *b, bool staticLookup)
{
- if (candidates.isEmpty())
- return;
+ QSet<ClassOrNamespace *> bindingsVisited;
+ QList<ClassOrNamespace *> bindingsToVisit;
+ bindingsToVisit.append(b);
- Class *klass = candidates.first()->asClass();
+ while (! bindingsToVisit.isEmpty()) {
+ ClassOrNamespace *binding = bindingsToVisit.takeFirst();
+ if (! binding || bindingsVisited.contains(binding))
+ continue;
- QList<Scope *> todo;
- context.expand(klass->members(), context.visibleScopes(), &todo);
+ bindingsVisited.insert(binding);
+ bindingsToVisit += binding->usings();
- foreach (Scope *scope, todo) {
- if (! (scope->isClassScope() || scope->isEnumScope()))
- continue;
+ QList<Scope *> scopesToVisit;
+ QSet<Scope *> scopesVisited;
- addCompletionItem(scope->owner());
+ foreach (Symbol *bb, binding->symbols()) {
+ if (Class *k = bb->asClass())
+ scopesToVisit.append(k->members());
+ }
- for (unsigned i = 0; i < scope->symbolCount(); ++i) {
- Symbol *symbol = scope->symbolAt(i);
+ foreach (Enum *e, binding->enums())
+ scopesToVisit.append(e->members());
- if (symbol->type().isFriend())
- continue;
- else if (! staticLookup && (symbol->isTypedef() ||
- symbol->isEnum() ||
- symbol->isClass()))
+ while (! scopesToVisit.isEmpty()) {
+ Scope *scope = scopesToVisit.takeFirst();
+ if (! scope || scopesVisited.contains(scope))
continue;
- addCompletionItem(symbol);
+ scopesVisited.insert(scope);
+
+ addCompletionItem(scope->owner()); // add a completion item for the injected class name.
+
+ for (Scope::iterator it = scope->firstSymbol(); it != scope->lastSymbol(); ++it) {
+ Symbol *member = *it;
+ if (member->isFriend())
+ continue;
+ else if (! staticLookup && (member->isTypedef() ||
+ member->isEnum() ||
+ member->isClass()))
+ continue;
+
+ addCompletionItem(member);
+ }
}
}
}
bool CppCodeCompletion::completeQtMethod(const QList<LookupItem> &results,
- const LookupContext &context,
bool wantSignals)
{
if (results.isEmpty())
return false;
- ResolveClass resolveClass;
+ const LookupContext &context = typeOfExpression.context();
ConvertToCompletionItem toCompletionItem(this);
Overview o;
if (! namedTy) // not a class name.
continue;
- const QList<Symbol *> classObjects =
- resolveClass(namedTy->name(), p, context);
-
- if (classObjects.isEmpty())
+ ClassOrNamespace *b = context.lookupType(namedTy->name(), p.scope());
+ if (! b)
continue;
- Class *klass = classObjects.first()->asClass();
+ QList<ClassOrNamespace *>todo;
+ QSet<ClassOrNamespace *> processed;
+ QList<Scope *> scopes;
+ todo.append(b);
+ while (!todo.isEmpty()) {
+ ClassOrNamespace *binding = todo.takeLast();
+ if (!processed.contains(binding)) {
+ processed.insert(binding);
- QList<Scope *> todo;
- const QList<Scope *> visibleScopes = context.visibleScopes(p);
- context.expand(klass->members(), visibleScopes, &todo);
+ foreach (Symbol *s, binding->symbols())
+ if (Class *clazz = s->asClass())
+ scopes.append(clazz->members());
- foreach (Scope *scope, todo) {
+ todo.append(binding->usings());
+ }
+ }
+
+ foreach (Scope *scope, scopes) {
if (! scope->isClassScope())
continue;
void CppCodeCompletion::completions(QList<TextEditor::CompletionItem> *completions)
{
const int length = m_editor->position() - m_startPosition;
+ if (length < 0)
+ return;
+
const QString key = m_editor->textAt(m_startPosition, length);
if (length == 0)
}
}
-QList<TextEditor::CompletionItem> CppCodeCompletion::getCompletions()
+QList<TextEditor::CompletionItem> CppCodeCompletion::removeDuplicates(const QList<TextEditor::CompletionItem> &items)
{
- QList<TextEditor::CompletionItem> completionItems;
-
- completions(&completionItems);
-
- qStableSort(completionItems.begin(), completionItems.end(), completionItemLessThan);
-
// Remove duplicates
- QString lastKey;
QList<TextEditor::CompletionItem> uniquelist;
+ QSet<QString> processed;
- foreach (const TextEditor::CompletionItem &item, completionItems) {
- if (item.text != lastKey) {
+ foreach (const TextEditor::CompletionItem &item, items) {
+ if (! processed.contains(item.text)) {
+ processed.insert(item.text);
uniquelist.append(item);
- lastKey = item.text;
- } else {
- TextEditor::CompletionItem &lastItem = uniquelist.last();
- Symbol *symbol = qvariant_cast<Symbol *>(item.data);
- Symbol *lastSymbol = qvariant_cast<Symbol *>(lastItem.data);
-
- if (symbol && lastSymbol) {
- Function *funTy = symbol->type()->asFunctionType();
- Function *lastFunTy = lastSymbol->type()->asFunctionType();
- if (funTy && lastFunTy) {
- if (funTy->argumentCount() == lastFunTy->argumentCount())
- continue;
+ if (Symbol *symbol = qvariant_cast<Symbol *>(item.data)) {
+ if (Function *funTy = symbol->type()->asFunctionType()) {
+ if (funTy->hasArguments())
+ ++uniquelist.back().duplicateCount;
}
}
-
- ++lastItem.duplicateCount;
}
}
return uniquelist;
}
+QList<TextEditor::CompletionItem> CppCodeCompletion::getCompletions()
+{
+ QList<TextEditor::CompletionItem> completionItems;
+ completions(&completionItems);
+
+ return completionItems;
+}
+
void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
{
Symbol *symbol = 0;
}
} else if (! function->isAmbiguous()) {
if (completionSettings().m_spaceAfterFunctionName)
- extraChars += QLatin1Char(' ');
+ extraChars += QLatin1Char(' ');
extraChars += QLatin1Char('(');
// If the function doesn't return anything, automatically place the semicolon,
// Set empty map in order to avoid referencing old versions of the documents
// until the next completion
- typeOfExpression.setSnapshot(Snapshot());
+ typeOfExpression.reset();
}
int CppCodeCompletion::findStartOfName(int pos) const
class BaseTextEditor;
}
+namespace CPlusPlus {
+class LookupItem;
+class ClassOrNamespace;
+}
+
namespace CppTools {
namespace Internal {
void addCompletionItem(CPlusPlus::Symbol *symbol);
bool completeInclude(const QTextCursor &cursor);
+ void completePreprocessor();
- int globalCompletion(CPlusPlus::Symbol *lastVisibleSymbol,
- CPlusPlus::Document::Ptr thisDocument,
- const CPlusPlus::Snapshot &snapshot);
+ void globalCompletion(CPlusPlus::Scope *scope);
- bool completeConstructorOrFunction(const QList<CPlusPlus::LookupItem> &,
- const CPlusPlus::LookupContext &,
+ bool completeConstructorOrFunction(const QList<CPlusPlus::LookupItem> &results,
int endOfExpression, bool toolTipOnly);
- bool completeMember(const QList<CPlusPlus::LookupItem> &,
- const CPlusPlus::LookupContext &context);
-
- bool completeScope(const QList<CPlusPlus::LookupItem> &,
- const CPlusPlus::LookupContext &context);
+ bool completeMember(const QList<CPlusPlus::LookupItem> &results);
+ bool completeScope(const QList<CPlusPlus::LookupItem> &results);
- void completeNamespace(const QList<CPlusPlus::Symbol *> &candidates,
- const CPlusPlus::LookupContext &context);
+ void completeNamespace(CPlusPlus::ClassOrNamespace *binding);
- void completeClass(const QList<CPlusPlus::Symbol *> &candidates,
- const CPlusPlus::LookupContext &context,
+ void completeClass(CPlusPlus::ClassOrNamespace *b,
bool staticLookup = true);
bool completeConstructors(CPlusPlus::Class *klass);
- bool completeQtMethod(const QList<CPlusPlus::LookupItem> &,
- const CPlusPlus::LookupContext &context,
+ bool completeQtMethod(const QList<CPlusPlus::LookupItem> &results,
bool wantSignals);
- bool completeSignal(const QList<CPlusPlus::LookupItem> &results,
- const CPlusPlus::LookupContext &context)
- { return completeQtMethod(results, context, true); }
+ bool completeSignal(const QList<CPlusPlus::LookupItem> &results)
+ { return completeQtMethod(results, true); }
- bool completeSlot(const QList<CPlusPlus::LookupItem> &results,
- const CPlusPlus::LookupContext &context)
- { return completeQtMethod(results, context, false); }
+ bool completeSlot(const QList<CPlusPlus::LookupItem> &results)
+ { return completeQtMethod(results, false); }
int findStartOfName(int pos = -1) const;
+ int startCompletionHelper(TextEditor::ITextEditable *editor);
+
int startCompletionInternal(TextEditor::BaseTextEditor *edit,
const QString fileName,
unsigned line, unsigned column,
const QString &expression,
int endOfExpression);
+ QList<TextEditor::CompletionItem> removeDuplicates(const QList<TextEditor::CompletionItem> &items);
+
private:
bool objcKeywordsWanted() const;
+ static QStringList preprocessorCompletions;
+
CppModelManager *m_manager;
TextEditor::ITextEditable *m_editor;
int m_startPosition; // Position of the cursor from which completion started
#include <Scope.h>
#include <cplusplus/CppDocument.h>
-#include <cplusplus/CppBindings.h>
#include <cplusplus/Overview.h>
#include <QtCore/QTime>
doc->check();
FindUsages process(doc, snapshot);
- process.setGlobalNamespaceBinding(bind(doc, snapshot));
-
process(symbol);
usages = process.usages();
}
{
}
-QList<int> CppFindReferences::references(Symbol *symbol,
- Document::Ptr doc,
- const Snapshot& snapshot) const
+QList<int> CppFindReferences::references(Symbol *symbol, const LookupContext &context) const
{
QList<int> references;
- FindUsages findUsages(doc, snapshot);
- findUsages.setGlobalNamespaceBinding(bind(doc, snapshot));
+ FindUsages findUsages(context);
findUsages(symbol);
references = findUsages.references();
static void find_helper(QFutureInterface<Usage> &future,
const CppTools::CppModelManagerInterface::WorkingCopy workingCopy,
- Snapshot snapshot,
- Document::Ptr symbolDocument,
- DependencyTable dependencyTable,
+ const LookupContext context,
+ const DependencyTable dependencyTable,
Symbol *symbol)
{
QTime tm;
QStringList files(sourceFile);
if (symbol->isClass() || symbol->isForwardClassDeclaration()) {
- foreach (const Document::Ptr &doc, snapshot) {
+ foreach (const Document::Ptr &doc, context.snapshot()) {
if (doc->fileName() == sourceFile)
continue;
future.setProgressRange(0, files.size());
- ProcessFile process(workingCopy, snapshot, symbolDocument, symbol);
+ ProcessFile process(workingCopy, context.snapshot(), context.thisDocument(), symbol);
UpdateUI reduce(&future);
QtConcurrent::blockingMappedReduced<QList<Usage> > (files, process, reduce);
m_depsFuture = QtConcurrent::run(&dependencyTable, m_deps, _modelManager->snapshot());
}
-void CppFindReferences::findUsages(Document::Ptr symbolDocument, Symbol *symbol)
+void CppFindReferences::findUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context)
{
Find::SearchResult *search = _resultWindow->startNewSearch(Find::SearchResultWindow::SearchOnly);
connect(search, SIGNAL(activated(Find::SearchResultItem)),
this, SLOT(openEditor(Find::SearchResultItem)));
- findAll_helper(symbolDocument, symbol);
+ findAll_helper(symbol, context);
}
-void CppFindReferences::renameUsages(Document::Ptr symbolDocument, Symbol *symbol)
+void CppFindReferences::renameUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context)
{
if (const Identifier *id = symbol->identifier()) {
const QString textToReplace = QString::fromUtf8(id->chars(), id->size());
connect(search, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)),
SLOT(onReplaceButtonClicked(QString,QList<Find::SearchResultItem>)));
- findAll_helper(symbolDocument, symbol);
+ findAll_helper(symbol, context);
}
}
-void CppFindReferences::findAll_helper(Document::Ptr symbolDocument, Symbol *symbol)
+void CppFindReferences::findAll_helper(Symbol *symbol, const LookupContext &context)
{
if (! (symbol && symbol->identifier()))
return;
QFuture<Usage> result;
- result = QtConcurrent::run(&find_helper, workingCopy, snapshot, symbolDocument, m_deps, symbol);
+ result = QtConcurrent::run(&find_helper, workingCopy, context, m_deps, symbol);
m_watcher.setFuture(result);
Core::FutureProgress *progress = progressManager->addTask(result, tr("Searching"),
CppFindReferences(CppModelManagerInterface *modelManager);
virtual ~CppFindReferences();
- QList<int> references(CPlusPlus::Symbol *symbol,
- CPlusPlus::Document::Ptr doc,
- const CPlusPlus::Snapshot& snapshot) const;
+ QList<int> references(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context) const;
Q_SIGNALS:
void changed();
public:
- void findUsages(CPlusPlus::Document::Ptr symbolDocument,CPlusPlus::Symbol *symbol);
- void renameUsages(CPlusPlus::Document::Ptr symbolDocument,CPlusPlus::Symbol *symbol);
+ void findUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context);
+ void renameUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context);
void findMacroUses(const CPlusPlus::Macro ¯o);
void updateDependencyTable();
private:
- void findAll_helper(CPlusPlus::Document::Ptr symbolDocument, CPlusPlus::Symbol *symbol);
+ void findAll_helper(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context);
private:
QPointer<CppModelManagerInterface> _modelManager;
**************************************************************************/
#include <cplusplus/pp.h>
-#include <cplusplus/CppBindings.h>
#include <cplusplus/Overview.h>
#include <cplusplus/CheckUndefinedSymbols.h>
#include <Parser.h>
#include <Control.h>
-#include <cplusplus/LookupContext.h>
-
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtCore/QMutexLocker>
{
QPointer<CppModelManager> _modelManager;
Snapshot _snapshot;
- CppModelManager::WorkingCopy _workingCopy;
Document::Ptr _doc;
+ Document::CheckMode _mode;
public:
Process(QPointer<CppModelManager> modelManager,
- Snapshot snapshot,
+ Document::Ptr doc,
+ const Snapshot &snapshot,
const CppModelManager::WorkingCopy &workingCopy)
: _modelManager(modelManager),
_snapshot(snapshot),
- _workingCopy(workingCopy)
- { }
-
- LookupContext lookupContext(unsigned line, unsigned column) const
- { return lookupContext(_doc->findSymbolAt(line, column)); }
-
- LookupContext lookupContext(Symbol *symbol) const
+ _doc(doc),
+ _mode(Document::FastCheck)
{
- LookupContext context(symbol, Document::create(QLatin1String("<none>")), _doc, _snapshot);
- return context;
+
+ if (workingCopy.contains(_doc->fileName()))
+ _mode = Document::FullCheck;
}
- void operator()(Document::Ptr doc)
+ void operator()()
{
- _doc = doc;
-
- Document::CheckMode mode = Document::FastCheck;
-
- if (_workingCopy.contains(doc->fileName()))
- mode = Document::FullCheck;
-
- if (doc->isParsed() && mode == Document::FastCheck) {
- TranslationUnit *unit = doc->translationUnit();
- MemoryPool *pool = unit->memoryPool();
-
- Parser parser(unit);
- Semantic semantic(unit);
-
- Namespace *globalNamespace = doc->control()->newNamespace(0);
- doc->setGlobalNamespace(globalNamespace);
-
- Scope *globals = globalNamespace->members();
-
- while (parser.LA()) {
- unsigned start_declaration = parser.cursor();
- DeclarationAST *declaration = 0;
-
- if (parser.parseDeclaration(declaration)) {
- semantic.check(declaration, globals);
-
- } else {
- doc->translationUnit()->error(start_declaration, "expected a declaration");
- parser.rewind(start_declaration + 1);
- parser.skipUntilDeclaration();
- }
-
- parser.clearTemplateArgumentList();
- pool->reset();
- }
-
- } else {
- doc->parse();
- doc->check(mode);
-
- if (mode == Document::FullCheck) {
- // run the binding pass
- NamespaceBindingPtr ns = bind(doc, _snapshot);
-
- // check for undefined symbols.
- CheckUndefinedSymbols checkUndefinedSymbols(doc);
- checkUndefinedSymbols.setGlobalNamespaceBinding(ns);
-
- checkUndefinedSymbols(doc->translationUnit()->ast()); // ### FIXME
- }
- }
-
- doc->releaseTranslationUnit();
+ _doc->check(_mode);
+ _doc->releaseTranslationUnit();
if (_modelManager)
- _modelManager->emitDocumentUpdated(doc); // ### TODO: compress
+ _modelManager->emitDocumentUpdated(_doc); // ### TODO: compress
}
};
} // end of anonymous namespace
QString CppPreprocessor::tryIncludeFile(QString &fileName, IncludeType type, unsigned *revision)
{
+ if (type == IncludeGlobal) {
+ const QString fn = m_fileNameCache.value(fileName);
+
+ if (! fn.isEmpty()) {
+ fileName = fn;
+
+ if (revision)
+ *revision = 0;
+
+ return QString();
+ }
+ }
+
+ const QString originalFileName = fileName;
+ const QString contents = tryIncludeFile_helper(fileName, type, revision);
+ if (type == IncludeGlobal)
+ m_fileNameCache.insert(originalFileName, fileName);
+ return contents;
+}
+
+QString CppPreprocessor::tryIncludeFile_helper(QString &fileName, IncludeType type, unsigned *revision)
+{
QFileInfo fileInfo(fileName);
if (fileName == QLatin1String(pp_configuration_file) || fileInfo.isAbsolute()) {
QString contents;
m_todo.remove(fileName);
#ifndef ICHECK_BUILD
- Process process(m_modelManager, snapshot, m_workingCopy);
+ Process process(m_modelManager, doc, snapshot, m_workingCopy);
- process(doc);
+ process();
(void) switchDocument(previousDoc);
#else
m_addtionalEditorSupport.remove(editorSupport);
}
-QList<int> CppModelManager::references(CPlusPlus::Symbol *symbol,
- CPlusPlus::Document::Ptr doc,
- const CPlusPlus::Snapshot &snapshot)
+QList<int> CppModelManager::references(CPlusPlus::Symbol *symbol, const LookupContext &context)
{
- NamespaceBindingPtr glo = bind(doc, snapshot);
- return m_findReferences->references(LookupContext::canonicalSymbol(symbol, glo.data()), doc, snapshot);
+ return m_findReferences->references(symbol, context);
}
-void CppModelManager::findUsages(CPlusPlus::Document::Ptr symbolDocument, CPlusPlus::Symbol *symbol)
+void CppModelManager::findUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context)
{
if (symbol->identifier())
- m_findReferences->findUsages(symbolDocument, symbol);
+ m_findReferences->findUsages(symbol, context);
}
-void CppModelManager::renameUsages(CPlusPlus::Document::Ptr symbolDocument, CPlusPlus::Symbol *symbol)
+void CppModelManager::renameUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context)
{
if (symbol->identifier())
- m_findReferences->renameUsages(symbolDocument, symbol);
+ m_findReferences->renameUsages(symbol, context);
}
void CppModelManager::findMacroUsages(const CPlusPlus::Macro ¯o)
return editor->context().contains(uid);
}
+TokenCache *CppModelManager::tokenCache(TextEditor::ITextEditor *editor) const
+{ return editorSupport(editor)->tokenCache(); }
+
void CppModelManager::emitDocumentUpdated(Document::Ptr doc)
{ emit documentUpdated(doc); }
future.reportFinished();
}
-// Function that sorts headers and sources apart to be used for
-// MimeDB::findByFile() on a sequence of file names.
-class HeaderSourceSorter {
-public:
- explicit HeaderSourceSorter(QStringList *sources, QStringList *headers);
- void operator()(const Core::MimeType &, const QFileInfo &, const QString &);
-
-private:
- QStringList m_sourceMimeTypes;
- QStringList m_headerMimeTypes;
-
- QStringList *m_sources;
- QStringList *m_headers;
-};
-
-HeaderSourceSorter::HeaderSourceSorter(QStringList *sources, QStringList *headers) :
- m_sources(sources),
- m_headers(headers)
-{
- m_headerMimeTypes << QLatin1String("text/x-hdr") << QLatin1String("text/x-c++hdr");
- m_sourceMimeTypes << QLatin1String("text/x-csrc") << QLatin1String("text/x-c++src")
- << QLatin1String("text/x-objcsrc");
-}
-
-void HeaderSourceSorter::operator()(const Core::MimeType &mimeType, const QFileInfo &, const QString &name)
-{
- if (mimeType) {
- if (m_sourceMimeTypes.contains(mimeType.type())) {
- m_sources->append(name);
- } else if (m_headerMimeTypes.contains(mimeType.type())) {
- m_headers->append(name);
- }
- }
-}
-
void CppModelManager::parse(QFutureInterface<void> &future,
CppPreprocessor *preproc,
QStringList files)
if (files.isEmpty())
return;
- foreach (const QString &file, files)
- preproc->snapshot.remove(file);
+ const Core::MimeDatabase *mimeDb = Core::ICore::instance()->mimeDatabase();
+ Core::MimeType cSourceTy = mimeDb->findByType(QLatin1String("text/x-csrc"));
+ Core::MimeType cppSourceTy = mimeDb->findByType(QLatin1String("text/x-c++src"));
+ Core::MimeType mSourceTy = mimeDb->findByType(QLatin1String("text/x-objcsrc"));
QStringList sources;
QStringList headers;
- const Core::MimeDatabase *mimeDb = Core::ICore::instance()->mimeDatabase();
- mimeDb->findByFile(files.constBegin(), files.constEnd(),
- HeaderSourceSorter(&sources, &headers));
+
+ QStringList suffixes = cSourceTy.suffixes();
+ suffixes += cppSourceTy.suffixes();
+ suffixes += mSourceTy.suffixes();
+
+ foreach (const QString &file, files) {
+ QFileInfo info(file);
+
+ preproc->snapshot.remove(file);
+
+ if (suffixes.contains(info.suffix()))
+ sources.append(file);
+ else
+ headers.append(file);
+ }
const int sourceCount = sources.size();
files = sources;
if (future.isCanceled())
break;
- // Change the priority of the background parser thread to idle.
- QThread::currentThread()->setPriority(QThread::IdlePriority);
-
const QString fileName = files.at(i);
const bool isSourceFile = i < sourceCount;
if (isSourceFile)
preproc->resetEnvironment();
-
- // Restore the previous thread priority.
- QThread::currentThread()->setPriority(QThread::NormalPriority);
}
future.setProgressValue(files.size());
inline Core::ICore *core() const { return m_core; }
- bool isCppEditor(Core::IEditor *editor) const; // ### private
+ virtual bool isCppEditor(Core::IEditor *editor) const;
CppEditorSupport *editorSupport(TextEditor::ITextEditor *editor) const
{ return m_editorSupport.value(editor); }
+ virtual CPlusPlus::TokenCache *tokenCache(TextEditor::ITextEditor *editor) const;
+
void emitDocumentUpdated(CPlusPlus::Document::Ptr doc);
void stopEditorSelectionsUpdate()
virtual void addEditorSupport(AbstractEditorSupport *editorSupport);
virtual void removeEditorSupport(AbstractEditorSupport *editorSupport);
- virtual QList<int> references(CPlusPlus::Symbol *symbol,
- CPlusPlus::Document::Ptr doc,
- const CPlusPlus::Snapshot &snapshot);
+ virtual QList<int> references(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context);
- virtual void findUsages(CPlusPlus::Document::Ptr symbolDocument, CPlusPlus::Symbol *symbol);
- virtual void renameUsages(CPlusPlus::Document::Ptr symbolDocument, CPlusPlus::Symbol *symbol);
+ virtual void renameUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context);
+ virtual void findUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context);
virtual void findMacroUsages(const CPlusPlus::Macro ¯o);
};
#endif
-using namespace CPlusPlus;
class CppPreprocessor: public CPlusPlus::Client
{
public:
{ return m_todo; }
public: // attributes
- Snapshot snapshot;
+ CPlusPlus::Snapshot snapshot;
protected:
CPlusPlus::Document::Ptr switchDocument(CPlusPlus::Document::Ptr doc);
bool includeFile(const QString &absoluteFilePath, QString *result, unsigned *revision);
QString tryIncludeFile(QString &fileName, IncludeType type, unsigned *revision);
+ QString tryIncludeFile_helper(QString &fileName, IncludeType type, unsigned *revision);
void mergeEnvironment(CPlusPlus::Document::Ptr doc);
- virtual void macroAdded(const Macro ¯o);
- virtual void passedMacroDefinitionCheck(unsigned offset, const Macro ¯o);
+ virtual void macroAdded(const CPlusPlus::Macro ¯o);
+ virtual void passedMacroDefinitionCheck(unsigned offset, const CPlusPlus::Macro ¯o);
virtual void failedMacroDefinitionCheck(unsigned offset, const QByteArray &name);
virtual void startExpandingMacro(unsigned offset,
- const Macro ¯o,
+ const CPlusPlus::Macro ¯o,
const QByteArray &originalText,
bool inCondition,
- const QVector<MacroArgumentReference> &actuals);
- virtual void stopExpandingMacro(unsigned offset, const Macro ¯o);
+ const QVector<CPlusPlus::MacroArgumentReference> &actuals);
+ virtual void stopExpandingMacro(unsigned offset, const CPlusPlus::Macro ¯o);
virtual void startSkippingBlocks(unsigned offset);
virtual void stopSkippingBlocks(unsigned offset);
virtual void sourceNeeded(QString &fileName, IncludeType type,
#ifndef ICHECK_BUILD
QPointer<CppModelManager> m_modelManager;
#endif
- Environment env;
- Preprocessor preprocess;
+ CPlusPlus::Environment env;
+ CPlusPlus::Preprocessor preprocess;
QStringList m_includePaths;
QStringList m_systemIncludePaths;
CppModelManagerInterface::WorkingCopy m_workingCopy;
QStringList m_projectFiles;
QStringList m_frameworkPaths;
QSet<QString> m_included;
- Document::Ptr m_currentDoc;
+ CPlusPlus::Document::Ptr m_currentDoc;
QSet<QString> m_todo;
QSet<QString> m_processed;
unsigned m_revision;
+ QHash<QString, QString> m_fileNameCache;
};
} // namespace Internal
#include <QtCore/QStringList>
#include <QtCore/QFuture>
+namespace Core {
+ class IEditor;
+}
+
+namespace CPlusPlus {
+ class LookupContext;
+ class TokenCache;
+}
+
namespace ProjectExplorer {
class Project;
}
+namespace TextEditor {
+ class ITextEditor;
+}
+
namespace CppTools {
class AbstractEditorSupport;
+namespace Internal {
+class CppEditorSupport;
+}
+
class CPPTOOLS_EXPORT CppModelManagerInterface : public QObject
{
Q_OBJECT
static CppModelManagerInterface *instance();
+ virtual bool isCppEditor(Core::IEditor *editor) const = 0;
+
virtual WorkingCopy workingCopy() const = 0;
virtual CPlusPlus::Snapshot snapshot() const = 0;
virtual void removeEditorSupport(AbstractEditorSupport *editorSupport) = 0;
virtual QList<int> references(CPlusPlus::Symbol *symbol,
- CPlusPlus::Document::Ptr doc,
- const CPlusPlus::Snapshot &snapshot) = 0;
+ const CPlusPlus::LookupContext &context) = 0;
- virtual void renameUsages(CPlusPlus::Document::Ptr symbolDocument, CPlusPlus::Symbol *symbol) = 0;
- virtual void findUsages(CPlusPlus::Document::Ptr symbolDocument, CPlusPlus::Symbol *symbol) = 0;
+ virtual void renameUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context) = 0;
+ virtual void findUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context) = 0;
virtual void findMacroUsages(const CPlusPlus::Macro ¯o) = 0;
+ virtual CPlusPlus::TokenCache *tokenCache(TextEditor::ITextEditor *editor) const = 0;
+
Q_SIGNALS:
void documentUpdated(CPlusPlus::Document::Ptr doc);
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "cpprefactoringchanges.h"
+
+using namespace CPlusPlus;
+using namespace CppTools;
+using namespace TextEditor;
+
+CppRefactoringChanges::CppRefactoringChanges(const Snapshot &snapshot,
+ CppModelManagerInterface *modelManager)
+ : m_snapshot(snapshot)
+ , m_modelManager(modelManager)
+ , m_workingCopy(modelManager->workingCopy())
+{
+ Q_ASSERT(modelManager);
+}
+
+QStringList CppRefactoringChanges::apply()
+{
+ const QStringList changedFiles = TextEditor::RefactoringChanges::apply();
+ m_modelManager->updateSourceFiles(changedFiles);
+ return changedFiles;
+}
+
+Document::Ptr CppRefactoringChanges::parsedDocumentForFile(const QString &fileName) const
+{
+ Document::Ptr doc = m_snapshot.document(fileName);
+
+ QString source;
+ if (m_workingCopy.contains(fileName)) {
+ QPair<QString, unsigned> workingCopy = m_workingCopy.get(fileName);
+ if (doc && doc->editorRevision() == workingCopy.second)
+ return doc;
+ else
+ source = workingCopy.first;
+ } else {
+ QFile file(fileName);
+ if (! file.open(QFile::ReadOnly))
+ return Document::Ptr();
+
+ source = QTextStream(&file).readAll(); // ### FIXME read bytes, and remove the convert below
+ file.close();
+ }
+
+ doc = m_snapshot.documentFromSource(source.toLatin1(), fileName);
+ doc->check();
+ return doc;
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef CPPREFACTORINGCHANGES_H
+#define CPPREFACTORINGCHANGES_H
+
+#include <cplusplus/CppDocument.h>
+
+#include <cpptools/cppmodelmanagerinterface.h>
+#include <cpptools/cpptools_global.h>
+
+#include <texteditor/refactoringchanges.h>
+
+namespace CppTools {
+
+class CPPTOOLS_EXPORT CppRefactoringChanges: public TextEditor::RefactoringChanges
+{
+public:
+ CppRefactoringChanges(const CPlusPlus::Snapshot &snapshot, CppModelManagerInterface *modelManager);
+
+ virtual QStringList apply();
+
+ const CPlusPlus::Snapshot &snapshot() const
+ { return m_snapshot; }
+
+ CPlusPlus::Document::Ptr parsedDocumentForFile(const QString &fileName) const;
+
+private:
+ CPlusPlus::Snapshot m_snapshot;
+ CppModelManagerInterface *m_modelManager;
+ CppModelManagerInterface::WorkingCopy m_workingCopy;
+};
+
+} // namespace CppTools
+
+#endif // CPPREFACTORINGCHANGES_H
searchsymbols.h \
cppdoxygen.h \
cppfilesettingspage.h \
- cppfindreferences.h
+ cppfindreferences.h \
+ cpprefactoringchanges.h
SOURCES += completionsettingspage.cpp \
cppclassesfilter.cpp \
cppdoxygen.cpp \
cppfilesettingspage.cpp \
abstracteditorsupport.cpp \
- cppfindreferences.cpp
+ cppfindreferences.cpp \
+ cpprefactoringchanges.cpp
FORMS += completionsettingspage.ui \
cppfilesettingspage.ui
{
_textEditor = textEditor;
- if (! _textEditor)
+ if (_textEditor) {
+ if (TextEditor::BaseTextEditor *ed = qobject_cast<TextEditor::BaseTextEditor *>(_textEditor->widget()))
+ _tokenCache.setDocument(ed->document());
+ } else {
return;
+ }
connect(_textEditor, SIGNAL(contentsChanged()), this, SIGNAL(contentsChanged()));
connect(this, SIGNAL(contentsChanged()), this, SLOT(updateDocument()));
return 0;
}
+TokenCache *CppEditorSupport::tokenCache()
+{
+ return &_tokenCache;
+}
+
int CppEditorSupport::updateDocumentInterval() const
{ return _updateDocumentInterval; }
{
_revision = editorRevision();
- if (TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor*>(_textEditor->widget())) {
- const QList<QTextEdit::ExtraSelection> selections =
- edit->extraSelections(TextEditor::BaseTextEditor::CodeWarningsSelection);
-
+ if (qobject_cast<TextEditor::BaseTextEditor*>(_textEditor->widget()) != 0) {
_modelManager->stopEditorSelectionsUpdate();
}
#include <QSharedPointer>
#include <QTextCursor>
#include <cplusplus/CppDocument.h>
+#include <cplusplus/TokenCache.h>
QT_BEGIN_NAMESPACE
class QTimer;
QString contents();
unsigned editorRevision() const;
+ CPlusPlus::TokenCache *tokenCache();
+
Q_SIGNALS:
void contentsChanged();
QFuture<void> _documentParser;
QString _cachedContents;
unsigned _revision;
+ CPlusPlus::TokenCache _tokenCache;
};
} // namespace Internal
-<plugin name="CVS" version="2.0.80" compatVersion="2.0.80">
+<plugin name="CVS" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>CVS integration.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
- <dependency name="Core" version="2.0.80"/>
- <dependency name="VCSBase" version="2.0.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
+ <dependency name="Core" version="2.1.80"/>
+ <dependency name="VCSBase" version="2.1.80"/>
</dependencyList>
</plugin>
case DeleteOperation:
case AnnotateOperation:
break;
+ case MoveOperation:
case OpenOperation:
case CreateRepositoryOperation:
case SnapshotOperations:
return m_plugin->vcsDelete(fi.absolutePath(), fi.fileName());
}
+bool CVSControl::vcsMove(const QString &from, const QString &to)
+{
+ Q_UNUSED(from);
+ Q_UNUSED(to);
+ return false;
+}
+
bool CVSControl::vcsCreateRepository(const QString &)
{
return false;
return true;
}
-bool CVSControl::managesDirectory(const QString &directory) const
-{
- return m_plugin->managesDirectory(directory);
-}
-
-QString CVSControl::findTopLevelForDirectory(const QString &directory) const
+bool CVSControl::managesDirectory(const QString &directory, QString *topLevel) const
{
- return m_plugin->findTopLevelForDirectory(directory);
+ return m_plugin->managesDirectory(directory, topLevel);
}
void CVSControl::emitRepositoryChanged(const QString &s)
explicit CVSControl(CVSPlugin *plugin);
virtual QString displayName() const;
- virtual bool managesDirectory(const QString &directory) const;
- virtual QString findTopLevelForDirectory(const QString &directory) const;
+ virtual bool managesDirectory(const QString &directory, QString *topLevel = 0) const;
virtual bool supportsOperation(Operation operation) const;
virtual bool vcsOpen(const QString &fileName);
virtual bool vcsAdd(const QString &fileName);
virtual bool vcsDelete(const QString &filename);
+ virtual bool vcsMove(const QString &from, const QString &to);
virtual bool vcsCreateRepository(const QString &directory);
virtual QString vcsCreateSnapshot(const QString &topLevel);
virtual QStringList vcsSnapshots(const QString &topLevel);
// CVS returns the diff exit code (1 if files differ), which is
// undistinguishable from a "file not found" error, unfortunately.
- const CVSResponse response = runCVS(workingDir, args, m_settings.timeOutMS(), false, codec);
+ const CVSResponse response =
+ runCVS(workingDir, args, m_settings.timeOutMS(), 0, codec);
switch (response.result) {
case CVSResponse::NonNullExitCode:
case CVSResponse::Ok:
return;
QStringList args;
args << QLatin1String("update") << QLatin1String("-C") << state.topLevel();
- const CVSResponse revertResponse = runCVS(state.topLevel(), args, m_settings.timeOutMS(), true);
+ const CVSResponse revertResponse =
+ runCVS(state.topLevel(), args, m_settings.timeOutMS(),
+ SshPasswordPrompt|ShowStdOutInLogWindow);
if (revertResponse.result == CVSResponse::Ok) {
cvsVersionControl()->emitRepositoryChanged(state.topLevel());
} else {
QTC_ASSERT(state.hasFile(), return)
QStringList args;
args << QLatin1String("diff") << state.relativeCurrentFile();
- const CVSResponse diffResponse = runCVS(state.currentFileTopLevel(), args, m_settings.timeOutMS(), false);
+ const CVSResponse diffResponse =
+ runCVS(state.currentFileTopLevel(), args, m_settings.timeOutMS(), 0);
switch (diffResponse.result) {
case CVSResponse::Ok:
return; // Not modified, diff exit code 0
// revert
args.clear();
args << QLatin1String("update") << QLatin1String("-C") << state.relativeCurrentFile();
- const CVSResponse revertResponse = runCVS(state.currentFileTopLevel(), args, m_settings.timeOutMS(), true);
+ const CVSResponse revertResponse =
+ runCVS(state.currentFileTopLevel(), args, m_settings.timeOutMS(),
+ SshPasswordPrompt|ShowStdOutInLogWindow);
if (revertResponse.result == CVSResponse::Ok) {
cvsVersionControl()->emitFilesChanged(QStringList(state.currentFile()));
}
// We need the "Examining <subdir>" stderr output to tell
// where we are, so, have stdout/stderr channels merged.
QStringList args = QStringList(QLatin1String("status"));
- const CVSResponse response = runCVS(workingDir, args, m_settings.timeOutMS(), false, 0, true);
+ const CVSResponse response =
+ runCVS(workingDir, args, m_settings.timeOutMS(), MergeOutputChannels);
if (response.result != CVSResponse::Ok)
return;
// Get list of added/modified/deleted files and purge out undesired ones
QStringList args = QStringList(QLatin1String("commit"));
args << QLatin1String("-F") << messageFile;
args.append(fileList);
- const CVSResponse response = runCVS(m_commitRepository, args, m_settings.longTimeOutMS(), true);
+ const CVSResponse response =
+ runCVS(m_commitRepository, args, m_settings.longTimeOutMS(),
+ SshPasswordPrompt|ShowStdOutInLogWindow);
return response.result == CVSResponse::Ok ;
}
QStringList args;
args << QLatin1String("log");
args.append(files);
- const CVSResponse response = runCVS(workingDir, args, m_settings.timeOutMS(), false, codec);
+ const CVSResponse response =
+ runCVS(workingDir, args, m_settings.timeOutMS(),
+ SshPasswordPrompt, codec);
if (response.result != CVSResponse::Ok)
return;
QStringList args(QLatin1String("update"));
args.push_back(QLatin1String("-dR"));
args.append(state.relativeCurrentProject());
- const CVSResponse response = runCVS(state.currentProjectTopLevel(), args, m_settings.longTimeOutMS(), true);
+ const CVSResponse response =
+ runCVS(state.currentProjectTopLevel(), args, m_settings.longTimeOutMS(),
+ SshPasswordPrompt|ShowStdOutInLogWindow);
if (response.result == CVSResponse::Ok)
cvsVersionControl()->emitRepositoryChanged(state.currentProjectTopLevel());
}
if (!revision.isEmpty())
args << QLatin1String("-r") << revision;
args << file;
- const CVSResponse response = runCVS(workingDir, args, m_settings.timeOutMS(), false, codec);
+ const CVSResponse response =
+ runCVS(workingDir, args, m_settings.timeOutMS(),
+ SshPasswordPrompt, codec);
if (response.result != CVSResponse::Ok)
return;
QTC_ASSERT(state.hasProject(), return)
QStringList args;
args << QLatin1String("status") << state.relativeCurrentProject();
- const CVSResponse response = runCVS(state.currentProjectTopLevel(), args, m_settings.timeOutMS(), false);
+ const CVSResponse response =
+ runCVS(state.currentProjectTopLevel(), args, m_settings.timeOutMS(), 0);
if (response.result == CVSResponse::Ok)
showOutputInEditor(tr("Project status"), response.stdOut, VCSBase::RegularCommandOutput, state.currentProjectTopLevel(), 0);
}
bool CVSPlugin::describe(const QString &file, const QString &changeNr, QString *errorMessage)
{
- const QString toplevel = findTopLevelForDirectory(QFileInfo(file).absolutePath());
- if (toplevel.isEmpty()) {
+
+ QString toplevel;
+ const bool manages = managesDirectory(QFileInfo(file).absolutePath(), &toplevel);
+ if (!manages || toplevel.isEmpty()) {
*errorMessage = msgCannotFindTopLevel(file);
return false;
}
// Run log to obtain commit id and details
QStringList args;
args << QLatin1String("log") << (QLatin1String("-r") + changeNr) << file;
- const CVSResponse logResponse = runCVS(toplevel, args, m_settings.timeOutMS(), false);
+ const CVSResponse logResponse =
+ runCVS(toplevel, args, m_settings.timeOutMS(), SshPasswordPrompt);
if (logResponse.result != CVSResponse::Ok) {
*errorMessage = logResponse.message;
return false;
args.clear();
args << QLatin1String("log") << QLatin1String("-d") << (dateS + QLatin1Char('<') + nextDayS);
- const CVSResponse repoLogResponse = runCVS(toplevel, args, m_settings.longTimeOutMS(), false);
+ const CVSResponse repoLogResponse =
+ runCVS(toplevel, args, m_settings.longTimeOutMS(), SshPasswordPrompt);
if (repoLogResponse.result != CVSResponse::Ok) {
*errorMessage = repoLogResponse.message;
return false;
// Run log
QStringList args(QLatin1String("log"));
args << (QLatin1String("-r") + it->revisions.front().revision) << it->file;
- const CVSResponse logResponse = runCVS(repositoryPath, args, m_settings.timeOutMS(), false);
+ const CVSResponse logResponse =
+ runCVS(repositoryPath, args, m_settings.timeOutMS(), SshPasswordPrompt);
if (logResponse.result != CVSResponse::Ok) {
*errorMessage = logResponse.message;
return false;
args << m_settings.cvsDiffOptions << QLatin1String("-r") << previousRev
<< QLatin1String("-r") << it->revisions.front().revision
<< it->file;
- const CVSResponse diffResponse = runCVS(repositoryPath, args, m_settings.timeOutMS(), false, codec);
+ const CVSResponse diffResponse =
+ runCVS(repositoryPath, args, m_settings.timeOutMS(), 0, codec);
switch (diffResponse.result) {
case CVSResponse::Ok:
case CVSResponse::NonNullExitCode: // Diff exit code != 0
<< Core::EditorManager::instance()->currentEditor());
}
-static inline QString processStdErr(QProcess &proc)
-{
- return QString::fromLocal8Bit(proc.readAllStandardError()).remove(QLatin1Char('\r'));
-}
-
-// Format log entry for command
-static inline QString msgExecutionLogEntry(const QString &workingDir, const QString &executable, const QStringList &arguments)
-{
- //: Executing: <executable> <arguments>
- const QString args = arguments.join(QString(QLatin1Char(' ')));
- if (workingDir.isEmpty())
- return CVSPlugin::tr("Executing: %1 %2\n").arg(executable, args);
- return CVSPlugin::tr("Executing in %1: %2 %3\n").
- arg(QDir::toNativeSeparators(workingDir), executable, args);
-}
-
// Run CVS. At this point, file arguments must be relative to
// the working directory (see above).
CVSResponse CVSPlugin::runCVS(const QString &workingDirectory,
const QStringList &arguments,
int timeOut,
- bool showStdOutInOutputWindow, QTextCodec *outputCodec,
- bool mergeStderr)
+ unsigned flags,
+ QTextCodec *outputCodec)
{
const QString executable = m_settings.cvsCommand;
CVSResponse response;
response.message =tr("No cvs executable specified!");
return response;
}
- // Fix files and compile complete arguments
- const QStringList allArgs = m_settings.addOptions(arguments);
-
- const QString outputText = msgExecutionLogEntry(workingDirectory, executable, allArgs);
- VCSBase::VCSBaseOutputWindow::instance()->appendCommand(outputText);
-
- if (CVS::Constants::debug)
- qDebug() << "runCVS" << timeOut << outputText;
-
// Run, connect stderr to the output window
- Utils::SynchronousProcess process;
- if (!workingDirectory.isEmpty())
- process.setWorkingDirectory(workingDirectory);
-
- if (mergeStderr)
- process.setProcessChannelMode(QProcess::MergedChannels);
-
- process.setTimeout(timeOut);
- process.setStdOutCodec(outputCodec);
-
- process.setStdErrBufferedSignalsEnabled(true);
- VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
- connect(&process, SIGNAL(stdErrBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
-
- // connect stdout to the output window if desired
- if (showStdOutInOutputWindow) {
- process.setStdOutBufferedSignalsEnabled(true);
- connect(&process, SIGNAL(stdOutBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
- }
+ const Utils::SynchronousProcessResponse sp_resp =
+ runVCS(workingDirectory, executable,
+ m_settings.addOptions(arguments),
+ timeOut, flags, outputCodec);
- const Utils::SynchronousProcessResponse sp_resp = process.run(executable, allArgs);
response.result = CVSResponse::OtherError;
response.stdErr = sp_resp.stdErr;
response.stdOut = sp_resp.stdOut;
break;
case Utils::SynchronousProcessResponse::FinishedError:
response.result = CVSResponse::NonNullExitCode;
- response.message = tr("The process terminated with exit code %1.").arg(sp_resp.exitCode);
break;
case Utils::SynchronousProcessResponse::TerminatedAbnormally:
- response.message = tr("The process terminated abnormally.");
- break;
case Utils::SynchronousProcessResponse::StartFailed:
- response.message = tr("Could not start cvs '%1'. Please check your settings in the preferences.").arg(executable);
- break;
case Utils::SynchronousProcessResponse::Hang:
- response.message = tr("CVS did not respond within timeout limit (%1 ms).").arg(timeOut);
break;
}
+
if (response.result != CVSResponse::Ok)
- VCSBase::VCSBaseOutputWindow::instance()->appendError(response.message);
+ response.message = sp_resp.exitMessage(executable, timeOut);
return response;
}
{
QStringList args;
args << QLatin1String("add") << rawFileName;
- const CVSResponse response = runCVS(workingDir, args, m_settings.timeOutMS(), true);
+ const CVSResponse response =
+ runCVS(workingDir, args, m_settings.timeOutMS(),
+ SshPasswordPrompt|ShowStdOutInLogWindow);
return response.result == CVSResponse::Ok;
}
{
QStringList args;
args << QLatin1String("remove") << QLatin1String("-f") << rawFileName;
- const CVSResponse response = runCVS(workingDir, args, m_settings.timeOutMS(), true);
+ const CVSResponse response =
+ runCVS(workingDir, args, m_settings.timeOutMS(),
+ SshPasswordPrompt|ShowStdOutInLogWindow);
return response.result == CVSResponse::Ok;
}
/* CVS has a "CVS" directory in each directory it manages. The top level
* is the first directory under the directory that does not have it. */
-bool CVSPlugin::managesDirectory(const QString &directory) const
+bool CVSPlugin::managesDirectory(const QString &directory, QString *topLevel /* = 0 */) const
{
+ if (topLevel)
+ topLevel->clear();
+ bool manages = false;
const QDir dir(directory);
- const bool rc = dir.exists() && managesDirectory(dir);
- if (CVS::Constants::debug)
- qDebug() << "CVSPlugin::managesDirectory" << directory << rc;
- return rc;
+ do {
+ if (!dir.exists() || !checkCVSDirectory(dir))
+ break;
+ manages = true;
+ if (!topLevel)
+ break;
+ /* Recursing up, the top level is a child of the first directory that does
+ * not have a "CVS" directory. The starting directory must be a managed
+ * one. Go up and try to find the first unmanaged parent dir. */
+ QDir lastDirectory = dir;
+ for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) {
+ if (!checkCVSDirectory(parentDir)) {
+ *topLevel = lastDirectory.absolutePath();
+ break;
+ }
+ }
+ } while (false);
+ if (CVS::Constants::debug) {
+ QDebug nsp = qDebug().nospace();
+ nsp << "CVSPlugin::managesDirectory" << directory << manages;
+ if (topLevel)
+ nsp << *topLevel;
+ }
+ return manages;
}
-bool CVSPlugin::managesDirectory(const QDir &directory) const
+bool CVSPlugin::checkCVSDirectory(const QDir &directory) const
{
const QString cvsDir = directory.absoluteFilePath(QLatin1String("CVS"));
return QFileInfo(cvsDir).isDir();
}
-QString CVSPlugin::findTopLevelForDirectory(const QString &directory) const
-{
- // Debug wrapper
- const QString rc = findTopLevelForDirectoryI(directory);
- if (CVS::Constants::debug)
- qDebug() << "CVSPlugin::findTopLevelForDirectory" << directory << rc;
- return rc;
-}
-
-QString CVSPlugin::findTopLevelForDirectoryI(const QString &directory) const
-{
- /* Recursing up, the top level is a child of the first directory that does
- * not have a "CVS" directory. The starting directory must be a managed
- * one. Go up and try to find the first unmanaged parent dir. */
- QDir lastDirectory = QDir(directory);
- if (!lastDirectory.exists() || !managesDirectory(lastDirectory))
- return QString();
- for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) {
- if (!managesDirectory(parentDir))
- return lastDirectory.absolutePath();
- }
- return QString();
-}
-
CVSControl *CVSPlugin::cvsVersionControl() const
{
return static_cast<CVSControl *>(versionControl());
// IVersionControl
bool vcsAdd(const QString &workingDir, const QString &fileName);
bool vcsDelete(const QString &workingDir, const QString &fileName);
- bool managesDirectory(const QString &directory) const;
- QString findTopLevelForDirectory(const QString &directory) const;
+ bool managesDirectory(const QString &directory, QString *topLevel = 0) const;
static CVSPlugin *cvsPluginInstance();
CVSResponse runCVS(const QString &workingDirectory,
const QStringList &arguments,
int timeOut,
- bool showStdOutInOutputWindow, QTextCodec *outputCodec = 0,
- bool mergeStderr = false);
+ unsigned flags, QTextCodec *outputCodec = 0);
void annotate(const QString &workingDir, const QString &file,
const QString &revision = QString(), int lineNumber= -1);
void filelog(const QString &workingDir,
const QStringList &files = QStringList(),
bool enableAnnotationContextMenu = false);
- bool managesDirectory(const QDir &directory) const;
+ bool checkCVSDirectory(const QDir &directory) const;
QString findTopLevelForDirectoryI(const QString &directory) const;
void startCommit(const QString &workingDir, const QStringList &files = QStringList());
bool commit(const QString &messageFile, const QStringList &subVersionFileList);
-<plugin name="Debugger" version="2.0.80" compatVersion="2.0.80">
+<plugin name="Debugger" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Debugger integration.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="CppEditor" version="2.0.80"/><!-- Debugger plugin adds items to the editor's context menu -->
- <dependency name="ProjectExplorer" version="2.0.80"/>
- <dependency name="Core" version="2.0.80"/>
- <dependency name="Find" version="2.0.80"/>
+ <dependency name="CppEditor" version="2.1.80"/><!-- Debugger plugin adds items to the editor's context menu -->
+ <dependency name="ProjectExplorer" version="2.1.80"/>
+ <dependency name="Core" version="2.1.80"/>
+ <dependency name="Find" version="2.1.80"/>
</dependencyList>
<argumentList>
<argument name="-disable-cdb">Disable Cdb debugger engine</argument>
<argument name="-disable-gdb">Disable Gdb debugger engine</argument>
<argument name="-disable-sdb">Disable Qt Script debugger engine</argument>
+ <argument name="-disable-tcf">Disable Tcf debugger engine</argument>
<argument name="-debug" parameter="pid-or-corefile">Attach to Process-Id or Core file</argument>
<argument name="-wincrashevent" parameter="event-handle">Event handle used for attaching to crashed processes</argument>
</argumentList>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AttachTcfDialog</class>
+ <widget class="QDialog" name="AttachTcfDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>310</width>
+ <height>224</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Start Debugger</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>9</number>
+ </property>
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="channelLabel">
+ <property name="text">
+ <string>Host and port:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="channelLineEdit">
+ <property name="text">
+ <string notr="true">localhost:5115</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="architectureLabel">
+ <property name="text">
+ <string>Architecture:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="architectureComboBox"/>
+ </item>
+ <item row="2" column="1">
+ <widget class="QCheckBox" name="useServerStartScriptCheckBox"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="useServerStartScriptLabel">
+ <property name="text">
+ <string>Use server start script:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="Utils::PathChooser" name="serverStartScript" native="true"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="serverStartScriptLabel">
+ <property name="text">
+ <string>Server start script:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Utils::PathChooser</class>
+ <extends>QWidget</extends>
+ <header location="global">utils/pathchooser.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
+ <widget class="QLabel" name="labelFileName">
+ <property name="text">
+ <string>File name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEditFileName"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="labelLineNumber">
+ <property name="text">
+ <string>Line number:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="lineEditLineNumber"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="labelFunction">
+ <property name="text">
+ <string>Function:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="lineEditFunction"/>
+ </item>
+ <item row="3" column="0">
<widget class="QLabel" name="labelCondition">
<property name="text">
<string>Condition:</string>
</property>
</widget>
</item>
- <item row="0" column="1">
+ <item row="3" column="1">
<widget class="QLineEdit" name="lineEditCondition"/>
</item>
- <item row="1" column="0">
+ <item row="4" column="0">
<widget class="QLabel" name="labelIgnoreCount">
<property name="text">
<string>Ignore count:</string>
</property>
</widget>
</item>
- <item row="1" column="1">
- <widget class="QSpinBox" name="spinBoxIgnoreCount">
- <property name="layoutDirection">
- <enum>Qt::LeftToRight</enum>
- </property>
- <property name="maximum">
- <number>999999999</number>
+ <item row="4" column="1">
+ <widget class="QLineEdit" name="lineEditIgnoreCount"/>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="labelThreadSpec">
+ <property name="text">
+ <string>Thread specification:</string>
</property>
</widget>
</item>
+ <item row="5" column="1">
+ <widget class="QLineEdit" name="lineEditThreadSpec"/>
+ </item>
</layout>
</item>
<item>
#include "debuggeractions.h"
#include "debuggermanager.h"
+#include "debuggerstringutils.h"
#include "stackframe.h"
#include <texteditor/basetextmark.h>
#include <utils/qtcassert.h>
+#include <QtCore/QByteArray>
#include <QtCore/QDebug>
#include <QtCore/QTextStream>
#include <QtCore/QFileInfo>
// Compare file names case insensitively on Windows.
static inline bool fileNameMatch(const QString &f1, const QString &f2)
{
- return f1.compare(f2,
#ifdef Q_OS_WIN
- Qt::CaseInsensitive
+ return f1.compare(f2, Qt::CaseInsensitive) == 0;
#else
- Qt::CaseSensitive
+ return f1 == f2;
#endif
- ) == 0;
}
namespace Debugger {
QIcon icon() const
{
- const BreakHandler *handler = DebuggerManager::instance()->breakHandler();
+ const BreakHandler *handler = m_data->handler();
if (!m_enabled)
return handler->disabledBreakpointIcon();
return m_pending ? handler->pendingBreakPointIcon() : handler->breakpointIcon();
return;
BreakHandler *handler = m_data->handler();
- handler->removeBreakpoint(handler->indexOf(m_data));
+ handler->removeBreakpoint(m_data);
handler->saveBreakpoints();
handler->updateMarkers();
}
//
//////////////////////////////////////////////////////////////////
-BreakpointData::BreakpointData(BreakHandler *handler)
+BreakpointData::BreakpointData()
{
- //qDebug() << "CREATE BREAKPOINTDATA" << this;
- m_handler = handler;
+ m_handler = 0;
enabled = true;
pending = true;
+ type = BreakpointType;
marker = 0;
m_markerLineNumber = 0;
bpMultiple = false;
-//#if defined(Q_OS_MAC)
-// // full names do not work on Mac/MI
+ bpEnabled = true;
useFullPath = false;
-//#else
-// //where = m_manager->shortName(data->fileName);
-// useFullPath = true;
-//#endif
}
BreakpointData::~BreakpointData()
{
removeMarker();
- //qDebug() << "DESTROY BREAKPOINTDATA" << this;
}
void BreakpointData::removeMarker()
<< "</td><td>" << m_markerLineNumber << "</td></tr>"
<< "<tr><td>" << BreakHandler::tr("Breakpoint Number:")
<< "</td><td>" << bpNumber << "</td></tr>"
- << "<tr><td>" << BreakHandler::tr("Breakpoint Address:")
- << "</td><td>" << bpAddress << "</td></tr>"
+ << "<tr><td>" << BreakHandler::tr("Breakpoint Type:")
+ << "</td><td>"
+ << (type == BreakpointType ? BreakHandler::tr("Breakpoint")
+ : type == WatchpointType ? BreakHandler::tr("Watchpoint")
+ : BreakHandler::tr("Unknown breakpoint type"))
+ << "</td></tr>"
<< "</table><br><hr><table>"
<< "<tr><th>" << BreakHandler::tr("Property")
<< "</th><th>" << BreakHandler::tr("Requested")
<< "</td><td>" << funcName << "</td><td>" << bpFuncName << "</td></tr>"
<< "<tr><td>" << BreakHandler::tr("Line Number:")
<< "</td><td>" << lineNumber << "</td><td>" << bpLineNumber << "</td></tr>"
+ << "<tr><td>" << BreakHandler::tr("Breakpoint Address:")
+ << "</td><td>" << address << "</td><td>" << bpAddress << "</td></tr>"
<< "<tr><td>" << BreakHandler::tr("Corrected Line Number:")
<< "</td><td>-</td><td>" << bpCorrectedLineNumber << "</td></tr>"
<< "<tr><td>" << BreakHandler::tr("Condition:")
<< "</td><td>" << condition << "</td><td>" << bpCondition << "</td></tr>"
<< "<tr><td>" << BreakHandler::tr("Ignore Count:")
<< "</td><td>" << ignoreCount << "</td><td>" << bpIgnoreCount << "</td></tr>"
+ << "<tr><td>" << BreakHandler::tr("Thread Specification:")
+ << "</td><td>" << threadSpec << "</td><td>" << bpThreadSpec << "</td></tr>"
<< "</table></body></html>";
return rc;
}
{
QString rc;
QTextStream str(&rc);
- str << BreakHandler::tr("Marker File:") << m_markerFileName << ' '
- << BreakHandler::tr("Marker Line:") << m_markerLineNumber << ' '
- << BreakHandler::tr("Breakpoint Number:") << bpNumber << ' '
- << BreakHandler::tr("Breakpoint Address:") << bpAddress << '\n'
- << BreakHandler::tr("File Name:")
+ str << BreakHandler::tr("Marker File:") << ' ' << m_markerFileName << '\n'
+ << BreakHandler::tr("Marker Line:") << ' ' << m_markerLineNumber << '\n'
+ << BreakHandler::tr("Breakpoint Number:") << ' ' << bpNumber << '\n'
+ << BreakHandler::tr("Breakpoint Type:") << ' '
+ << (type == BreakpointType ? BreakHandler::tr("Breakpoint")
+ : type == WatchpointType ? BreakHandler::tr("Watchpoint")
+ : BreakHandler::tr("Unknown breakpoint type")) << '\n'
+ << BreakHandler::tr("File Name:") << ' '
<< fileName << " -- " << bpFileName << '\n'
- << BreakHandler::tr("Function Name:")
+ << BreakHandler::tr("Function Name:") << ' '
<< funcName << " -- " << bpFuncName << '\n'
- << BreakHandler::tr("Line Number:")
+ << BreakHandler::tr("Line Number:") << ' '
<< lineNumber << " -- " << bpLineNumber << '\n'
- << BreakHandler::tr("Condition:")
+ << BreakHandler::tr("Breakpoint Address:") << ' '
+ << address << " -- " << bpAddress << '\n'
+ << BreakHandler::tr("Condition:") << ' '
<< condition << " -- " << bpCondition << '\n'
- << BreakHandler::tr("Ignore Count:")
- << ignoreCount << " -- " << bpIgnoreCount << '\n';
+ << BreakHandler::tr("Ignore Count:") << ' '
+ << ignoreCount << " -- " << bpIgnoreCount << '\n'
+ << BreakHandler::tr("Thread Specification:") << ' '
+ << threadSpec << " -- " << bpThreadSpec << '\n';
return rc;
}
BreakHandler::BreakHandler(DebuggerManager *manager, QObject *parent) :
QAbstractTableModel(parent),
- m_breakpointIcon(QLatin1String(":/debugger/images/breakpoint_16.png")),
- m_disabledBreakpointIcon(QLatin1String(":/debugger/images/breakpoint_disabled_16.png")),
- m_pendingBreakPointIcon(QLatin1String(":/debugger/images/breakpoint_pending_16.png")),
+ m_breakpointIcon(_(":/debugger/images/breakpoint_16.png")),
+ m_disabledBreakpointIcon(_(":/debugger/images/breakpoint_disabled_16.png")),
+ m_pendingBreakPointIcon(_(":/debugger/images/breakpoint_pending_16.png")),
+ m_watchpointIcon(_(":/debugger/images/watchpoint.png")),
m_manager(manager)
{
}
int BreakHandler::columnCount(const QModelIndex &parent) const
{
- return parent.isValid() ? 0 : 7;
+ return parent.isValid() ? 0 : 8;
}
int BreakHandler::rowCount(const QModelIndex &parent) const
m_inserted.clear();
}
-int BreakHandler::findBreakpoint(const BreakpointData &needle) const
+BreakpointData *BreakHandler::findSimilarBreakpoint(const BreakpointData &needle) const
{
// Search a breakpoint we might refer to.
for (int index = 0; index != size(); ++index) {
- const BreakpointData *data = at(index);
+ BreakpointData *data = m_bp[index];
// Clear hit.
- if (data->bpNumber == needle.bpNumber)
- return index;
+ if (data->bpNumber == needle.bpNumber
+ && !data->bpNumber.isEmpty()
+ && data->bpNumber.toInt() != 0)
+ return data;
+ // Clear miss.
+ if (data->type != needle.type)
+ continue;
+ // We have numbers, but they are different.
+ if (!data->bpNumber.isEmpty() && !needle.bpNumber.isEmpty()
+ && !data->bpNumber.startsWith(needle.bpNumber)
+ && !needle.bpNumber.startsWith(data->bpNumber))
+ continue;
// At least at a position we were looking for.
// FIXME: breaks multiple breakpoints at the same location
- if (fileNameMatch(data->fileName, needle.bpFileName)
+ if (!data->fileName.isEmpty()
+ && fileNameMatch(data->fileName, needle.bpFileName)
&& data->lineNumber == needle.bpLineNumber)
- return index;
+ return data;
}
- return -1;
-}
-
-int BreakHandler::findBreakpoint(const QString &fileName, int lineNumber) const
-{
- if (lineNumber <= 0) {
- QByteArray address = fileName.toLatin1();
- for (int index = 0; index != size(); ++index)
- if (at(index)->bpAddress == address)
- return index;
- } else {
- for (int index = 0; index != size(); ++index)
- if (at(index)->isLocatedAt(fileName, lineNumber))
- return index;
- }
- return -1;
+ return 0;
}
-BreakpointData *BreakHandler::findBreakpoint(int bpNumber) const
+BreakpointData *BreakHandler::findBreakpointByNumber(int bpNumber) const
{
if (!size())
return 0;
return 0;
}
+int BreakHandler::findWatchPointIndexByAddress(const QByteArray &a) const
+{
+ for (int index = size() - 1; index >= 0; --index) {
+ BreakpointData *bd = at(index);
+ if (bd->type == BreakpointData::WatchpointType && bd->address == a)
+ return index;
+ }
+ return -1;
+}
+
+bool BreakHandler::watchPointAt(quint64 address) const
+{
+ const QByteArray addressBA = QByteArray("0x") + QByteArray::number(address, 16);
+ return findWatchPointIndexByAddress(addressBA) != -1;
+}
+
void BreakHandler::saveBreakpoints()
{
QList<QVariant> list;
for (int index = 0; index != size(); ++index) {
const BreakpointData *data = at(index);
QMap<QString, QVariant> map;
+ // Do not persist Watchpoints.
+ //if (data->type == BreakpointData::WatchpointType)
+ // continue;
+ if (data->type != BreakpointData::BreakpointType)
+ map.insert(_("type"), data->type);
if (!data->fileName.isEmpty())
- map.insert(QLatin1String("filename"), data->fileName);
+ map.insert(_("filename"), data->fileName);
if (!data->lineNumber.isEmpty())
- map.insert(QLatin1String("linenumber"), data->lineNumber);
+ map.insert(_("linenumber"), data->lineNumber);
if (!data->funcName.isEmpty())
- map.insert(QLatin1String("funcname"), data->funcName);
+ map.insert(_("funcname"), data->funcName);
+ if (!data->address.isEmpty())
+ map.insert(_("address"), data->address);
if (!data->condition.isEmpty())
- map.insert(QLatin1String("condition"), data->condition);
+ map.insert(_("condition"), data->condition);
if (!data->ignoreCount.isEmpty())
- map.insert(QLatin1String("ignorecount"), data->ignoreCount);
+ map.insert(_("ignorecount"), data->ignoreCount);
+ if (!data->threadSpec.isEmpty())
+ map.insert(_("threadspec"), data->threadSpec);
if (!data->enabled)
- map.insert(QLatin1String("disabled"), QLatin1String("1"));
+ map.insert(_("disabled"), _("1"));
if (data->useFullPath)
- map.insert(QLatin1String("usefullpath"), QLatin1String("1"));
+ map.insert(_("usefullpath"), _("1"));
list.append(map);
}
m_manager->setSessionValue("Breakpoints", list);
clear();
foreach (const QVariant &var, list) {
const QMap<QString, QVariant> map = var.toMap();
- BreakpointData *data = new BreakpointData(this);
- QVariant v = map.value(QLatin1String("filename"));
+ BreakpointData *data = new BreakpointData;
+ QVariant v = map.value(_("filename"));
if (v.isValid())
data->fileName = v.toString();
- v = map.value(QLatin1String("linenumber"));
+ v = map.value(_("linenumber"));
if (v.isValid())
data->lineNumber = v.toString().toLatin1();
- v = map.value(QLatin1String("condition"));
+ v = map.value(_("condition"));
if (v.isValid())
data->condition = v.toString().toLatin1();
- v = map.value(QLatin1String("ignorecount"));
+ v = map.value(_("address"));
+ if (v.isValid())
+ data->address = v.toString().toLatin1();
+ v = map.value(_("ignorecount"));
if (v.isValid())
data->ignoreCount = v.toString().toLatin1();
- v = map.value(QLatin1String("funcname"));
+ v = map.value(_("threadspec"));
+ if (v.isValid())
+ data->threadSpec = v.toString().toLatin1();
+ v = map.value(_("funcname"));
if (v.isValid())
data->funcName = v.toString();
- v = map.value(QLatin1String("disabled"));
+ v = map.value(_("disabled"));
if (v.isValid())
data->enabled = !v.toInt();
- v = map.value(QLatin1String("usefullpath"));
+ v = map.value(_("usefullpath"));
if (v.isValid())
data->useFullPath = bool(v.toInt());
+ v = map.value(_("type"));
+ if (v.isValid())
+ data->type = BreakpointData::Type(v.toInt());
data->setMarkerFileName(data->fileName);
data->setMarkerLineNumber(data->lineNumber.toInt());
append(data);
data->bpCorrectedLineNumber.clear();
data->bpCondition.clear();
data->bpIgnoreCount.clear();
+ data->bpThreadSpec.clear();
data->bpAddress.clear();
// Keep marker data if it was primary.
if (data->markerFileName() != data->fileName)
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
static QString headers[] = {
tr("Number"), tr("Function"), tr("File"), tr("Line"),
- tr("Condition"), tr("Ignore"), tr("Address")
+ tr("Condition"), tr("Ignore"), tr("Threads"), tr("Address")
};
return headers[section];
}
if (role == Qt::UserRole)
return data->enabled;
if (role == Qt::DecorationRole) {
+ if (data->type == BreakpointData::WatchpointType)
+ return m_watchpointIcon;
if (!data->enabled)
return m_disabledBreakpointIcon;
return data->pending ? m_pendingBreakPointIcon : m_breakpointIcon;
const QString str = data->pending ? data->funcName : data->bpFuncName;
return str.isEmpty() ? empty : str;
}
+ if (role == Qt::UserRole + 1)
+ return data->funcName;
break;
case 2:
if (role == Qt::DisplayRole) {
}
if (role == Qt::UserRole)
return data->useFullPath;
+ if (role == Qt::UserRole + 1)
+ return data->fileName;
break;
case 3:
if (role == Qt::DisplayRole) {
const QString str = data->pending ? data->lineNumber : data->bpLineNumber;
return str.isEmpty() ? empty : str;
}
+ if (role == Qt::UserRole + 1)
+ return data->lineNumber;
break;
case 4:
if (role == Qt::DisplayRole)
return data->pending ? data->condition : data->bpCondition;
if (role == Qt::ToolTipRole)
return tr("Breakpoint will only be hit if this condition is met.");
+ if (role == Qt::UserRole + 1)
+ return data->condition;
break;
case 5:
if (role == Qt::DisplayRole)
return data->pending ? data->ignoreCount : data->bpIgnoreCount;
if (role == Qt::ToolTipRole)
return tr("Breakpoint will only be hit after being ignored so many times.");
+ if (role == Qt::UserRole + 1)
+ return data->ignoreCount;
+ break;
case 6:
- if (role == Qt::DisplayRole)
+ if (role == Qt::DisplayRole) {
+ if (data->pending)
+ return !data->threadSpec.isEmpty() ? data->threadSpec : tr("(all)");
+ else
+ return !data->bpThreadSpec.isEmpty() ? data->bpThreadSpec : tr("(all)");
+ }
+ if (role == Qt::ToolTipRole)
+ return tr("Breakpoint will only be hit in the specified thread(s).");
+ if (role == Qt::UserRole + 1)
+ return data->threadSpec;
+ break;
+ case 7:
+ if (role == Qt::DisplayRole) {
+ if (data->type == BreakpointData::WatchpointType)
+ return data->address;
return data->bpAddress;
+ }
break;
}
if (role == Qt::ToolTipRole)
bool BreakHandler::setData(const QModelIndex &mi, const QVariant &value, int role)
{
- if (role != Qt::EditRole)
- return false;
-
BreakpointData *data = at(mi.row());
+
+ if (role == Qt::UserRole + 1) {
+ if (data->enabled != value.toBool()) {
+ toggleBreakpointEnabled(data);
+ layoutChanged();
+ }
+ return true;
+ }
+
+ if (role == Qt::UserRole + 2) {
+ if (data->useFullPath != value.toBool()) {
+ data->useFullPath = value.toBool();
+ layoutChanged();
+ }
+ return true;
+ }
+
+ //if (role != Qt::EditRole)
+ // return false;
+
switch (mi.column()) {
- case 0: {
- if (data->enabled != value.toBool()) {
- toggleBreakpointEnabled(data);
- dataChanged(mi, mi);
+ case 1: {
+ QString val = value.toString();
+ if (data->funcName != val) {
+ data->funcName = val;
+ layoutChanged();
}
return true;
}
case 2: {
- if (data->useFullPath != value.toBool()) {
- data->useFullPath = value.toBool();
- dataChanged(mi, mi);
+ QString val = value.toString();
+ if (data->fileName != val) {
+ data->fileName = val;
+ layoutChanged();
+ }
+ return true;
+ }
+ case 3: {
+ QByteArray val = value.toString().toLatin1();
+ if (data->lineNumber != val) {
+ data->lineNumber = val;
+ layoutChanged();
}
return true;
}
case 4: {
- QString val = value.toString();
+ QByteArray val = value.toString().toLatin1();
if (val != data->condition) {
- data->condition = val.toLatin1();
- dataChanged(mi, mi);
+ data->condition = val;
+ layoutChanged();
}
return true;
}
case 5: {
- QString val = value.toString();
+ QByteArray val = value.toString().toLatin1();
if (val != data->ignoreCount) {
- data->ignoreCount = val.toLatin1();
- dataChanged(mi, mi);
+ data->ignoreCount = val;
+ layoutChanged();
+ }
+ return true;
+ }
+ case 6: {
+ QByteArray val = value.toString().toLatin1();
+ if (val != data->threadSpec) {
+ data->threadSpec = val;
+ layoutChanged();
}
return true;
}
void BreakHandler::append(BreakpointData *data)
{
+ data->m_handler = this;
m_bp.append(data);
m_inserted.append(data);
}
saveBreakpoints();
}
+void BreakHandler::removeBreakpoint(BreakpointData *data)
+{
+ removeBreakpointHelper(m_bp.indexOf(data));
+ emit layoutChanged();
+ saveBreakpoints();
+}
+
void BreakHandler::toggleBreakpointEnabled(BreakpointData *data)
{
QTC_ASSERT(data, return);
&& data->ignoreCount.isEmpty())
return;
}
- BreakpointData *data = new BreakpointData(this);
+ BreakpointData *data = new BreakpointData;
data->funcName = functionName;
append(data);
saveBreakpoints();
#ifndef DEBUGGER_BREAKHANDLER_H
#define DEBUGGER_BREAKHANDLER_H
+#include "breakpoint.h"
+
#include <QtCore/QObject>
#include <QtCore/QAbstractTableModel>
#include <QtGui/QIcon>
namespace Debugger {
-class DebuggerManager;
namespace Internal {
-class BreakpointMarker;
-class BreakHandler;
-
-//////////////////////////////////////////////////////////////////
-//
-// BreakpointData
-//
-//////////////////////////////////////////////////////////////////
-
-class BreakpointData
-{
-public:
- explicit BreakpointData(BreakHandler *handler);
- ~BreakpointData();
-
- void removeMarker();
- void updateMarker();
- QString toToolTip() const;
- QString toString() const;
- BreakHandler *handler() { return m_handler; }
-
- bool isLocatedAt(const QString &fileName, int lineNumber) const;
- bool conditionsMatch() const;
-
-private:
- // Intentionally unimplemented.
- // Making it copyable is tricky because of the markers.
- void operator=(const BreakpointData &);
- BreakpointData(const BreakpointData &);
-
- // Our owner
- BreakHandler *m_handler; // Not owned.
-
-public:
- bool enabled; // Should we talk to the debugger engine?
- bool pending; // Does the debugger engine know about us already?
-
- // This "user requested information" will get stored in the session.
- QString fileName; // Short name of source file.
- QByteArray condition; // Condition associated with breakpoint.
- QByteArray ignoreCount; // Ignore count associated with breakpoint.
- QByteArray lineNumber; // Line in source file.
- QString funcName; // Name of containing function.
- bool useFullPath; // Should we use the full path when setting the bp?
-
- // This is what gdb produced in response.
- QByteArray bpNumber; // Breakpoint number assigned by the debugger engine.
- QByteArray bpCondition; // Condition acknowledged by the debugger engine.
- QByteArray bpIgnoreCount;// Ignore count acknowledged by the debugger engine.
- QString bpFileName; // File name acknowledged by the debugger engine.
- QString bpFullName; // Full file name acknowledged by the debugger engine.
- QByteArray bpLineNumber; // Line number acknowledged by the debugger engine.
- QByteArray bpCorrectedLineNumber; // Acknowledged by the debugger engine.
- QString bpFuncName; // Function name acknowledged by the debugger engine.
- QByteArray bpAddress; // Address acknowledged by the debugger engine.
- bool bpMultiple; // Happens in constructors/gdb.
- bool bpEnabled; // Enable/disable command sent.
-
- void setMarkerFileName(const QString &fileName);
- QString markerFileName() const { return m_markerFileName; }
-
- void setMarkerLineNumber(int lineNumber);
- int markerLineNumber() const { return m_markerLineNumber; }
-
-private:
- // Taken from either user input or gdb responses.
- QString m_markerFileName; // Used to locate the marker.
- int m_markerLineNumber;
-
- // Our red blob in the editor.
- BreakpointMarker *marker;
-};
-
-
//////////////////////////////////////////////////////////////////
//
// BreakHandler
void removeAt(int index); // This also deletes the marker.
void clear(); // This also deletes all the marker.
int indexOf(BreakpointData *data) { return m_bp.indexOf(data); }
- // If lineNumber < 0, interpret fileName as address.
- int findBreakpoint(const QString &fileName, int lineNumber) const;
- int findBreakpoint(const BreakpointData &data) const; // Returns index.
- BreakpointData *findBreakpoint(int bpNumber) const;
+ // Find a breakpoint matching approximately the data in needle.bp*,
+ BreakpointData *findSimilarBreakpoint(const BreakpointData &needle) const;
+ BreakpointData *findBreakpointByNumber(int bpNumber) const;
+ int findWatchPointIndexByAddress(const QByteArray &a) const;
+ bool watchPointAt(quint64 address) const;
void updateMarkers();
QList<BreakpointData *> insertedBreakpoints() const;
void toggleBreakpointEnabled(BreakpointData *data);
void breakByFunction(const QString &functionName);
void removeBreakpoint(int index);
+ void removeBreakpoint(BreakpointData *data);
private:
friend class BreakpointMarker;
const QIcon m_breakpointIcon;
const QIcon m_disabledBreakpointIcon;
const QIcon m_pendingBreakPointIcon;
+ const QIcon m_watchpointIcon;
DebuggerManager *m_manager; // Not owned.
QList<BreakpointData *> m_bp;
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DEBUGGER_BREAKPOINT_H
+#define DEBUGGER_BREAKPOINT_H
+
+#include <QtCore/QString>
+
+namespace Debugger {
+class DebuggerManager;
+namespace Internal {
+
+class BreakpointMarker;
+class BreakHandler;
+
+//////////////////////////////////////////////////////////////////
+//
+// BreakpointData
+//
+//////////////////////////////////////////////////////////////////
+
+class BreakpointData
+{
+public:
+ BreakpointData();
+ ~BreakpointData();
+
+ void removeMarker();
+ void updateMarker();
+ QString toToolTip() const;
+ QString toString() const;
+ BreakHandler *handler() { return m_handler; }
+
+ bool isLocatedAt(const QString &fileName, int lineNumber) const;
+ bool conditionsMatch() const;
+
+private:
+ // Intentionally unimplemented.
+ // Making it copyable is tricky because of the markers.
+ void operator=(const BreakpointData &);
+ BreakpointData(const BreakpointData &);
+
+ // Our owner
+ BreakHandler *m_handler; // Not owned.
+ friend class BreakHandler;
+
+public:
+ enum Type { BreakpointType, WatchpointType };
+
+ bool enabled; // Should we talk to the debugger engine?
+ bool pending; // Does the debugger engine know about us already?
+ Type type; // Type of breakpoint.
+
+ // This "user requested information" will get stored in the session.
+ QString fileName; // Short name of source file.
+ QByteArray condition; // Condition associated with breakpoint.
+ QByteArray ignoreCount; // Ignore count associated with breakpoint.
+ QByteArray lineNumber; // Line in source file.
+ QByteArray address; // Address for watchpoints.
+ QByteArray threadSpec; // Thread specification.
+ QString funcName; // Name of containing function.
+ bool useFullPath; // Should we use the full path when setting the bp?
+
+ // This is what gdb produced in response.
+ QByteArray bpNumber; // Breakpoint number assigned by the debugger engine.
+ QByteArray bpCondition; // Condition acknowledged by the debugger engine.
+ QByteArray bpIgnoreCount;// Ignore count acknowledged by the debugger engine.
+ QString bpFileName; // File name acknowledged by the debugger engine.
+ QString bpFullName; // Full file name acknowledged by the debugger engine.
+ QByteArray bpLineNumber; // Line number acknowledged by the debugger engine.
+ QByteArray bpCorrectedLineNumber; // Acknowledged by the debugger engine.
+ QByteArray bpThreadSpec; // Thread spec acknowledged by the debugger engine.
+ QString bpFuncName; // Function name acknowledged by the debugger engine.
+ QByteArray bpAddress; // Address acknowledged by the debugger engine.
+ bool bpMultiple; // Happens in constructors/gdb.
+ bool bpEnabled; // Enable/disable command sent.
+
+ void setMarkerFileName(const QString &fileName);
+ QString markerFileName() const { return m_markerFileName; }
+
+ void setMarkerLineNumber(int lineNumber);
+ int markerLineNumber() const { return m_markerLineNumber; }
+
+private:
+ // Taken from either user input or gdb responses.
+ QString m_markerFileName; // Used to locate the marker.
+ int m_markerLineNumber;
+
+ // Our red blob in the editor.
+ BreakpointMarker *marker;
+};
+
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_BREAKPOINT_H
#include "breakwindow.h"
+#include "breakhandler.h"
+#include "threadshandler.h"
#include "debuggeractions.h"
#include "debuggermanager.h"
+#include "stackhandler.h"
#include "ui_breakcondition.h"
#include "ui_breakbyfunction.h"
void BreakWindow::showAddressColumn(bool on)
{
- setColumnHidden(6, !on);
+ setColumnHidden(7, !on);
}
static QModelIndexList normalizeIndexes(const QModelIndexList &list)
QTreeView::resizeEvent(ev);
}
+void BreakWindow::mouseDoubleClickEvent(QMouseEvent *ev)
+{
+ QModelIndex indexUnderMouse = indexAt(ev->pos());
+ if (indexUnderMouse.isValid() && indexUnderMouse.column() >= 4)
+ editBreakpoint(QModelIndexList() << indexUnderMouse);
+ QTreeView::mouseDoubleClickEvent(ev);
+}
+
void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
{
QMenu menu;
alwaysAdjustAction->setCheckable(true);
alwaysAdjustAction->setChecked(m_alwaysResizeColumnsToContents);
- QAction *editConditionAction =
- new QAction(tr("Edit Condition..."), &menu);
- editConditionAction->setEnabled(si.size() > 0);
+ QAction *editBreakpointAction =
+ new QAction(tr("Edit Breakpoint..."), &menu);
+ editBreakpointAction->setEnabled(si.size() > 0);
+
+ int threadId = m_manager->threadsHandler()->currentThreadId();
+ QString associateTitle = threadId == -1
+ ? tr("Associate Breakpoint With All Threads")
+ : tr("Associate Breakpoint With Thread %1").arg(threadId);
+ QAction *associateBreakpointAction = new QAction(associateTitle, &menu);
+ associateBreakpointAction->setEnabled(si.size() > 0);
QAction *synchronizeAction =
new QAction(tr("Synchronize Breakpoints"), &menu);
new QAction(tr("Set Breakpoint at \"catch\""), this);
menu.addAction(deleteAction);
- menu.addAction(editConditionAction);
+ menu.addAction(editBreakpointAction);
+ menu.addAction(associateBreakpointAction);
menu.addAction(toggleEnabledAction);
menu.addAction(pathAction);
menu.addSeparator();
resizeColumnsToContents();
else if (act == alwaysAdjustAction)
setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
- else if (act == editConditionAction)
- editConditions(si);
+ else if (act == editBreakpointAction)
+ editBreakpoint(si);
+ else if (act == associateBreakpointAction)
+ associateBreakpoint(si, threadId);
else if (act == synchronizeAction)
emit breakpointSynchronizationRequested();
else if (act == toggleEnabledAction)
void BreakWindow::setBreakpointsEnabled(const QModelIndexList &list, bool enabled)
{
foreach (const QModelIndex &idx, list)
- model()->setData(idx, enabled);
+ model()->setData(idx, enabled, Qt::UserRole + 1);
emit breakpointSynchronizationRequested();
}
{
foreach (const QModelIndex &idx, list) {
QModelIndex idx2 = idx.sibling(idx.row(), 2);
- model()->setData(idx2, fullpath);
+ model()->setData(idx2, fullpath, Qt::UserRole + 2);
}
emit breakpointSynchronizationRequested();
}
const int row = qMin(firstRow, model()->rowCount() - 1);
if (row >= 0)
setCurrentIndex(model()->index(row, 0));
+ emit breakpointSynchronizationRequested();
}
-void BreakWindow::editConditions(const QModelIndexList &list)
+void BreakWindow::editBreakpoint(const QModelIndexList &list)
{
QDialog dlg(this);
Ui::BreakCondition ui;
QModelIndex idx = list.front();
int row = idx.row();
dlg.setWindowTitle(tr("Conditions on Breakpoint %1").arg(row));
- ui.lineEditCondition->setText(model()->data(idx.sibling(row, 4)).toString());
- ui.spinBoxIgnoreCount->setValue(model()->data(idx.sibling(row, 5)).toInt());
+ int role = Qt::UserRole + 1;
+ ui.lineEditFunction->hide();
+ ui.labelFunction->hide();
+ ui.lineEditFileName->hide();
+ ui.labelFileName->hide();
+ ui.lineEditLineNumber->hide();
+ ui.labelLineNumber->hide();
+ QAbstractItemModel *m = model();
+ //ui.lineEditFunction->setText(
+ // m->data(idx.sibling(row, 1), role).toString());
+ //ui.lineEditFileName->setText(
+ // m->data(idx.sibling(row, 2), role).toString());
+ //ui.lineEditLineNumber->setText(
+ // m->data(idx.sibling(row, 3), role).toString());
+ ui.lineEditCondition->setText(
+ m->data(idx.sibling(row, 4), role).toString());
+ ui.lineEditIgnoreCount->setText(
+ m->data(idx.sibling(row, 5), role).toString());
+ ui.lineEditThreadSpec->setText(
+ m->data(idx.sibling(row, 6), role).toString());
if (dlg.exec() == QDialog::Rejected)
return;
foreach (const QModelIndex &idx, list) {
- model()->setData(idx.sibling(idx.row(), 4), ui.lineEditCondition->text());
- model()->setData(idx.sibling(idx.row(), 5), ui.spinBoxIgnoreCount->value());
+ //m->setData(idx.sibling(idx.row(), 1), ui.lineEditFunction->text());
+ //m->setData(idx.sibling(idx.row(), 2), ui.lineEditFileName->text());
+ //m->setData(idx.sibling(idx.row(), 3), ui.lineEditLineNumber->text());
+ m->setData(idx.sibling(idx.row(), 4), ui.lineEditCondition->text());
+ m->setData(idx.sibling(idx.row(), 5), ui.lineEditIgnoreCount->text());
+ m->setData(idx.sibling(idx.row(), 6), ui.lineEditThreadSpec->text());
}
emit breakpointSynchronizationRequested();
}
+void BreakWindow::associateBreakpoint(const QModelIndexList &list, int threadId)
+{
+ QString str;
+ if (threadId != -1)
+ str = QString::number(threadId);
+ foreach (const QModelIndex &idx, list)
+ model()->setData(idx.sibling(idx.row(), 6), str);
+ emit breakpointSynchronizationRequested();
+}
+
void BreakWindow::resizeColumnsToContents()
{
for (int i = model()->columnCount(); --i >= 0; )
/**************************************************************************
+QT_END_NAMESPACE
**
** This file is part of Qt Creator
**
void resizeEvent(QResizeEvent *ev);
void contextMenuEvent(QContextMenuEvent *ev);
void keyPressEvent(QKeyEvent *ev);
+ void mouseDoubleClickEvent(QMouseEvent *ev);
private:
void deleteBreakpoints(const QModelIndexList &list);
void deleteBreakpoints(QList<int> rows);
- void editConditions(const QModelIndexList &list);
+ void editBreakpoint(const QModelIndexList &list);
+ void associateBreakpoint(const QModelIndexList &list, int thread);
void setBreakpointsEnabled(const QModelIndexList &list, bool enabled);
void setBreakpointsFullPath(const QModelIndexList &list, bool fullpath);
static const char sourceFileQuoteC = '`';
BreakPoint::BreakPoint() :
+ type(Code),
lineNumber(-1),
address(0),
+ threadId(-1),
ignoreCount(0),
oneShot(false),
enabled(true)
{
}
-int BreakPoint::compare(const BreakPoint& rhs) const
-{
- if (lineNumber > rhs.lineNumber)
- return 1;
- if (lineNumber < rhs.lineNumber)
- return -1;
- if (address > rhs.address)
- return 1;
- if (address < rhs.address)
- return -1;
- if (ignoreCount > rhs.ignoreCount)
- return 1;
- if (ignoreCount < rhs.ignoreCount)
- return -1;
- if (oneShot && !rhs.oneShot)
- return 1;
- if (!oneShot && rhs.oneShot)
- return -1;
- if (enabled && !rhs.enabled)
- return 1;
- if (!enabled && rhs.enabled)
- return -1;
- if (const int fileCmp = fileName.compare(rhs.fileName))
- return fileCmp;
- if (const int funcCmp = funcName.compare(rhs.funcName))
- return funcCmp;
- if (const int condCmp = condition.compare(rhs.condition))
- return condCmp;
- return 0;
-}
-
void BreakPoint::clear()
{
+ type = Code;
ignoreCount = 0;
+ threadId = -1;
oneShot = false;
enabled = true;
clearExpressionData();
QDebug operator<<(QDebug dbg, const BreakPoint &bp)
{
- QDebug nsp = dbg.nospace();
- if (bp.address)
- nsp << "0x" << QString::number(bp.address, 16) << ' ';
- if (!bp.fileName.isEmpty()) {
- nsp << "fileName='" << bp.fileName << ':' << bp.lineNumber << '\'';
+ dbg.nospace() << bp.toString();
+ return dbg;
+}
+
+QString BreakPoint::toString() const
+{
+ QString rc;
+ QTextStream str(&rc);
+ str << (type == BreakPoint::Code ? "Code " : "Data ");
+ if (address) {
+ str.setIntegerBase(16);
+ str << "0x" << address << ' ';
+ str.setIntegerBase(10);
+ }
+ if (!fileName.isEmpty()) {
+ str << "fileName='" << fileName << ':' << lineNumber << '\'';
} else {
- nsp << "funcName='" << bp.funcName << '\'';
+ str << "funcName='" << funcName << '\'';
}
- if (!bp.condition.isEmpty())
- nsp << " condition='" << bp.condition << '\'';
- if (bp.ignoreCount)
- nsp << " ignoreCount=" << bp.ignoreCount;
- if (bp.enabled)
- nsp << " enabled";
- if (bp.oneShot)
- nsp << " oneShot";
- return dbg;
+ if (threadId >= 0)
+ str << " thread=" << threadId;
+ if (!condition.isEmpty())
+ str << " condition='" << condition << '\'';
+ if (ignoreCount)
+ str << " ignoreCount=" << ignoreCount;
+ str << (enabled ? " enabled" : " disabled");
+ if (oneShot)
+ str << " oneShot";
+ return rc;
}
QString BreakPoint::expression() const
return rc;
}
+static inline QString msgCannotSetBreakpoint(const QString &exp, const QString &why)
+{
+ return QString::fromLatin1("Unable to set breakpoint '%1' : %2").arg(exp, why);
+}
+
bool BreakPoint::apply(CIDebugBreakpoint *ibp, QString *errorMessage) const
{
const QString expr = expression();
if (debugBP)
qDebug() << Q_FUNC_INFO << *this << expr;
- const HRESULT hr = ibp->SetOffsetExpressionWide(reinterpret_cast<PCWSTR>(expr.utf16()));
+ HRESULT hr = ibp->SetOffsetExpressionWide(reinterpret_cast<PCWSTR>(expr.utf16()));
if (FAILED(hr)) {
- *errorMessage = QString::fromLatin1("Unable to set breakpoint '%1' : %2").
- arg(expr, CdbCore::msgComFailed("SetOffsetExpressionWide", hr));
+ *errorMessage = msgCannotSetBreakpoint(expr, CdbCore::msgComFailed("SetOffsetExpressionWide", hr));
return false;
}
// Pass Count is ignoreCount + 1
- ibp->SetPassCount(ignoreCount + 1u);
+ hr = ibp->SetPassCount(ignoreCount + 1u);
+ if (FAILED(hr))
+ qWarning("Error setting passcount %d %s ", ignoreCount, qPrintable(expr));
+ // Set up size for data breakpoints
+ if (type == Data) {
+ const ULONG size = 1u;
+ hr = ibp->SetDataParameters(size, DEBUG_BREAK_READ | DEBUG_BREAK_WRITE);
+ if (FAILED(hr)) {
+ const QString msg = QString::fromLatin1("Cannot set watch size to %1: %2").
+ arg(size).arg(CdbCore::msgComFailed("SetDataParameters", hr));
+ *errorMessage = msgCannotSetBreakpoint(expr, msg);
+ return false;
+ }
+ }
+ // Thread
+ if (threadId >= 0) {
+ hr = ibp->SetMatchThreadId(threadId);
+ if (FAILED(hr)) {
+ const QString msg = QString::fromLatin1("Cannot set thread id to %1: %2").
+ arg(threadId).arg(CdbCore::msgComFailed("SetMatchThreadId", hr));
+ *errorMessage = msgCannotSetBreakpoint(expr, msg);
+ return false;
+ }
+ }
+ // Flags
ULONG flags = 0;
if (enabled)
flags |= DEBUG_BREAKPOINT_ENABLED;
if (oneShot)
flags |= DEBUG_BREAKPOINT_ONE_SHOT;
- ibp->AddFlags(flags);
+ hr = ibp->AddFlags(flags);
+ if (FAILED(hr)) {
+ const QString msg = QString::fromLatin1("Cannot set flags to 0x%1: %2").
+ arg(flags, 0 ,16).arg(CdbCore::msgComFailed("AddFlags", hr));
+ *errorMessage = msgCannotSetBreakpoint(expr, msg);
+ return false;
+ }
return true;
}
unsigned long *id,
quint64 *address) const
{
- IDebugBreakpoint2* ibp = 0;
+ CIDebugBreakpoint* ibp = 0;
if (address)
*address = 0;
if (id)
*id = 0;
- HRESULT hr = debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &ibp);
+ const ULONG iType = type == Code ? DEBUG_BREAKPOINT_CODE : DEBUG_BREAKPOINT_DATA;
+ HRESULT hr = debugControl->AddBreakpoint2(iType, DEBUG_ANY_ID, &ibp);
if (FAILED(hr)) {
*errorMessage = msgCannotAddBreakPoint(CdbCore::msgComFailed("AddBreakpoint2", hr));
return false;
normalizedFileNameCache()->clear();
}
+static inline QString msgCannotRetrieveBreakpoint(const QString &why)
+{
+ return QString::fromLatin1("Cannot retrieve breakpoint: %1").arg(why);
+}
+
+static inline int threadIdOfBreakpoint(CIDebugBreakpoint *ibp)
+{
+ // Thread: E_NOINTERFACE indicates no thread has been set.
+ int threadId = -1;
+ ULONG iThreadId;
+ if (S_OK == ibp->GetMatchThreadId(&iThreadId))
+ threadId = iThreadId;
+ return threadId;
+}
+
bool BreakPoint::retrieve(CIDebugBreakpoint *ibp, QString *errorMessage)
{
clear();
+ // Get type
+ ULONG iType;
+ ULONG processorType;
+ HRESULT hr = ibp->GetType(&iType, &processorType);
+ if (FAILED(hr)) {
+ *errorMessage = msgCannotRetrieveBreakpoint(CdbCore::msgComFailed("GetType", hr));
+ return false;
+ }
+ type = iType == DEBUG_BREAKPOINT_CODE ? Code : Data;
+ // Get & parse expression
WCHAR wszBuf[MAX_PATH];
- const HRESULT hr =ibp->GetOffsetExpressionWide(wszBuf, MAX_PATH, 0);
+ hr =ibp->GetOffsetExpressionWide(wszBuf, MAX_PATH, 0);
if (FAILED(hr)) {
- *errorMessage = QString::fromLatin1("Cannot retrieve breakpoint: %1").
- arg(CdbCore::msgComFailed("GetOffsetExpressionWide", hr));
+ *errorMessage = msgCannotRetrieveBreakpoint(CdbCore::msgComFailed("GetOffsetExpressionWide", hr));
return false;
}
+ threadId = threadIdOfBreakpoint(ibp);
// Pass Count is ignoreCount + 1
ibp->GetPassCount(&ignoreCount);
if (ignoreCount)
if (!getBreakPointCount(debugControl, &count, errorMessage))
return false;
// retrieve one by one and parse
- for (ULONG b= 0; b < count; b++) {
- IDebugBreakpoint2 *ibp = 0;
+ for (ULONG b = 0; b < count; b++) {
+ CIDebugBreakpoint *ibp = 0;
const HRESULT hr = debugControl->GetBreakpointByIndex2(b, &ibp);
if (FAILED(hr)) {
*errorMessage = QString::fromLatin1("Cannot retrieve breakpoint %1: %2").
return QString::fromLatin1("Unable to find breakpoint with id %1: %2").arg(id).arg(why);
}
-IDebugBreakpoint2 *BreakPoint::breakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage)
+CIDebugBreakpoint *BreakPoint::breakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage)
{
CIDebugBreakpoint *ibp = 0;
const HRESULT hr = ctl->GetBreakpointById2(id, &ibp);
return true;
}
+// Change thread-id of a breakpoint
+static inline QString msgCannotSetBreakPointThread(unsigned long id, int tid, const QString &why)
+{
+ return QString::fromLatin1("Cannot set breakpoint %1 thread to %2: %3").arg(id).arg(tid).arg(why);
+}
+
+bool BreakPoint::setBreakPointThreadById(CIDebugControl *ctl, unsigned long id, int threadId, QString *errorMessage)
+{
+ if (debugBP)
+ qDebug() << Q_FUNC_INFO << id << threadId;
+ CIDebugBreakpoint *ibp = breakPointById(ctl, id, errorMessage);
+ if (!ibp) {
+ *errorMessage = msgCannotSetBreakPointThread(id, threadId, *errorMessage);
+ return false;
+ }
+ // Compare thread ids
+ const int oldThreadId = threadIdOfBreakpoint(ibp);
+ if (oldThreadId == threadId)
+ return true;
+ const ULONG newIThreadId = threadId == -1 ? DEBUG_ANY_ID : static_cast<ULONG>(threadId);
+ if (debugBP)
+ qDebug() << "Changing thread id of " << id << " from " << oldThreadId << " to " << threadId
+ << '(' << newIThreadId << ')';
+ const HRESULT hr = ibp->SetMatchThreadId(newIThreadId);
+ if (FAILED(hr)) {
+ *errorMessage = msgCannotSetBreakPointThread(id, threadId, *errorMessage);
+ return false;
+ }
+ return true;
}
+} // namespace CdbCore
struct BreakPoint
{
- BreakPoint();
+ enum Type { Code, // Stop in code.
+ Data // Stop when accessing address.
+ };
- int compare(const BreakPoint& rhs) const;
+ BreakPoint();
void clear();
void clearExpressionData();
QString expression() const;
- // Apply parameters
- bool apply(IDebugBreakpoint2 *ibp, QString *errorMessage) const;
- // Convenience to add to a IDebugControl4
+ // Apply parameters (with the exception of type, which is
+ // passed as a parameter to IDebugControl within add().
+ bool apply(CIDebugBreakpoint *ibp, QString *errorMessage) const;
+ // Convenience to add to a IDebugControl4.
bool add(CIDebugControl* debugControl,
QString *errorMessage,
unsigned long *id = 0,
quint64 *address = 0) const;
// Retrieve/parse breakpoints from the interfaces
- bool retrieve(IDebugBreakpoint2 *ibp, QString *errorMessage);
+ bool retrieve(CIDebugBreakpoint *ibp, QString *errorMessage);
bool parseExpression(const QString &expr);
// Retrieve all breakpoints from the engine
static bool getBreakPointCount(CIDebugControl* debugControl, ULONG *count, QString *errorMessage = 0);
static bool getBreakPoints(CIDebugControl* debugControl, QList<BreakPoint> *bps, QString *errorMessage);
// Control helpers
- static IDebugBreakpoint2 *breakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage);
+ static CIDebugBreakpoint *breakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage);
static bool removeBreakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage);
static bool setBreakPointEnabledById(CIDebugControl *ctl, unsigned long id, bool enabled, QString *errorMessage);
+ static bool setBreakPointThreadById(CIDebugControl *ctl, unsigned long id, int threadId, QString *errorMessage);
// Return a 'canonical' file (using '/' and capitalized drive letter)
static QString normalizeFileName(const QString &f);
static void clearNormalizeFileNameCache();
+ QString toString() const;
+ Type type;
QString fileName; // short name of source file
int lineNumber; // line in source file
QString funcName; // name of containing function
quint64 address;
+ int threadId;
QString condition; // condition associated with breakpoint
unsigned long ignoreCount; // ignore count associated with breakpoint
bool oneShot;
QDebug operator<<(QDebug, const BreakPoint &bp);
-inline bool operator==(const BreakPoint& b1, const BreakPoint& b2)
- { return b1.compare(b2) == 0; }
-inline bool operator!=(const BreakPoint& b1, const BreakPoint& b2)
- { return b1.compare(b2) != 0; }
-}
+} // namespace CdbCore
#endif // CDBCOREBREAKPOINTS_H
FORMS += $$PWD/cdboptionspagewidget.ui
}
+
+
+# Compile test on non-Windows platforms
+isEmpty(CDB_PATH) {
+false {
+
+HEADERS += \
+ $$PWD/cdbcom.h \
+ $$PWD/coreengine.h \
+ $$PWD/debugoutputbase.h \
+ $$PWD/debugeventcallbackbase.h \
+ $$PWD/symbolgroupcontext.h \
+ $$PWD/stacktracecontext.h \
+ $$PWD/breakpoint.h
+
+HEADERS += \
+ $$PWD/cdbdebugengine.h \
+ $$PWD/cdbdebugengine_p.h \
+ $$PWD/cdbdebugeventcallback.h \
+ $$PWD/cdbdebugoutput.h \
+ $$PWD/cdbsymbolgroupcontext.h \
+ $$PWD/cdbsymbolgroupcontext_tpl.h \
+ $$PWD/cdbstacktracecontext.h \
+ $$PWD/cdbbreakpoint.h \
+ $$PWD/cdbmodules.h \
+ $$PWD/cdbassembler.h \
+ $$PWD/cdboptions.h \
+ $$PWD/cdboptionspage.h \
+ $$PWD/cdbdumperhelper.h \
+ $$PWD/cdbsymbolpathlisteditor.h \
+ $$PWD/cdbexceptionutils.h
+
+SOURCES += \
+# $$PWD/coreengine.cpp \
+# $$PWD/debugoutputbase.cpp \
+# $$PWD/debugeventcallbackbase.cpp \
+# $$PWD/symbolgroupcontext.cpp \
+# $$PWD/stacktracecontext.cpp \
+# $$PWD/breakpoint.cpp
+
+SOURCES += \
+# $$PWD/cdbdebugengine.cpp \
+# $$PWD/cdbdebugeventcallback.cpp \
+ $$PWD/cdbdebugoutput.cpp \
+# $$PWD/cdbsymbolgroupcontext.cpp \
+ $$PWD/cdbstacktracecontext.cpp \
+ $$PWD/cdbbreakpoint.cpp \
+# $$PWD/cdbmodules.cpp \
+ $$PWD/cdbassembler.cpp \
+ $$PWD/cdboptions.cpp \
+ $$PWD/cdboptionspage.cpp \
+# $$PWD/cdbdumperhelper.cpp \
+ $$PWD/cdbsymbolpathlisteditor.cpp \
+# $$PWD/cdbexceptionutils.cpp
+
+FORMS += $$PWD/cdboptionspagewidget.ui
+INCLUDEPATH*=$$PWD
+DEPENDPATH*=$$PWD
+}
+}
+
enum { debugBP = 0 };
+// Convert breakpoint structs
+CdbCore::BreakPoint breakPointFromBreakPointData(const Debugger::Internal::BreakpointData &bpd)
+{
+ CdbCore::BreakPoint rc;
+ rc.type = bpd.type == Debugger::Internal::BreakpointData::BreakpointType ?
+ CdbCore::BreakPoint::Code : CdbCore::BreakPoint::Data;
+
+ if (rc.type == CdbCore::BreakPoint::Data) {
+ QByteArray addressBA = bpd.address;
+ if (addressBA.startsWith("0x"))
+ addressBA.remove(0, 2);
+ bool ok;
+ rc.address = addressBA.toULongLong(&ok, 16);
+ if (!ok)
+ qWarning("Cdb: Cannot convert watchpoint address '%s'", bpd.address.constData());
+ }
+ if (!bpd.threadSpec.isEmpty()) {
+ bool ok;
+ rc.threadId = bpd.threadSpec.toInt(&ok);
+ if (!ok)
+ qWarning("Cdb: Cannot convert breakpoint thread specification '%s'", bpd.address.constData());
+ }
+ rc.fileName = QDir::toNativeSeparators(bpd.fileName);
+ rc.condition = bpd.condition;
+ rc.funcName = bpd.funcName;
+ rc.ignoreCount = bpd.ignoreCount.isEmpty() ? 0 : bpd.ignoreCount.toInt();
+ rc.lineNumber = bpd.lineNumber.isEmpty() ? -1 : bpd.lineNumber.toInt();
+ rc.oneShot = false;
+ rc.enabled = bpd.enabled;
+ return rc;
+}
static inline QString msgCannotSetBreakAtFunction(const QString &func, const QString &why)
{
breakPointOk = ncdbbp.add(debugControl, &warning, &id, &address);
if (breakPointOk) {
if (debugBP)
- qDebug() << "Added " << id << " at " << address << ncdbbp;
+ qDebug("Added %lu at 0x%lx %s", id, address, qPrintable(ncdbbp.toString()));
handler->takeInsertedBreakPoint(nbd);
updateMarkers = true;
nbd->pending = false;
// Take over rest as is
nbd->bpCondition = nbd->condition;
nbd->bpIgnoreCount = nbd->ignoreCount;
+ nbd->bpThreadSpec = nbd->threadSpec;
nbd->bpFileName = nbd->fileName;
nbd->bpLineNumber = nbd->lineNumber;
nbd->bpFuncName = nbd->funcName;
foreach (BreakpointData *dbd, handler->takeDisabledBreakpoints())
if (!CdbCore::BreakPoint::setBreakPointEnabledById(debugControl, dbd->bpNumber.toUInt(), false, &warning))
warnings->push_back(warning);
+ // Check for modified thread ids.
+ for (int i = handler->size() - 1; i >= 0; i--) {
+ BreakpointData *bpd = handler->at(i);
+ if (bpd->threadSpec != bpd->bpThreadSpec) {
+ const int newThreadSpec = bpd->threadSpec.isEmpty() ? -1 : bpd->threadSpec.toInt();
+ if (CdbCore::BreakPoint::setBreakPointThreadById(debugControl, bpd->bpNumber.toUInt(), newThreadSpec, errorMessage)) {
+ bpd->bpThreadSpec = bpd->threadSpec;
+ } else {
+ qWarning("%s", qPrintable(*errorMessage));
+ }
+ }
+ }
if (updateMarkers)
handler->updateMarkers();
if (debugBP > 1) {
QList<CdbCore::BreakPoint> bps;
CdbCore::BreakPoint::getBreakPoints(debugControl, &bps, errorMessage);
- qDebug().nospace() << "### Breakpoints in engine: " << bps;
+ QDebug nsp = qDebug().nospace();
+ const int count = bps.size();
+ nsp <<"### Breakpoints in engine: " << count << '\n';
+ for (int i = 0; i < count; i++)
+ nsp << " #" << i << ' ' << bps.at(i) << '\n';
}
return true;
}
class QDebug;
QT_END_NAMESPACE
-// Convert breakpoint structs
-inline CdbCore::BreakPoint breakPointFromBreakPointData(const Debugger::Internal::BreakpointData &bpd)
-{
- CdbCore::BreakPoint rc;
- rc.fileName = QDir::toNativeSeparators(bpd.fileName);
- rc.condition = bpd.condition;
- rc.funcName = bpd.funcName;
- rc.ignoreCount = bpd.ignoreCount.isEmpty() ? 0 : bpd.ignoreCount.toInt();
- rc.lineNumber = bpd.lineNumber.isEmpty() ? -1 : bpd.lineNumber.toInt();
- rc.oneShot = false;
- rc.enabled = bpd.enabled;
- return rc;
-}
-
namespace Debugger {
namespace Internal {
+// Convert breakpoint structs
+CdbCore::BreakPoint breakPointFromBreakPointData(const Debugger::Internal::BreakpointData &bpd);
+
// Synchronize (halted) engine with BreakHandler.
bool synchronizeBreakPoints(CIDebugControl* ctl, CIDebugSymbols *syms,
BreakHandler *bh,
#ifndef CDBCOM_H
#define CDBCOM_H
+#include <QtCore/QtGlobal>
+
+#ifdef Q_OS_WIN
+
#include <windows.h>
#include <inc/dbgeng.h>
typedef IDebugSymbolGroup2 CIDebugSymbolGroup;
typedef IDebugBreakpoint2 CIDebugBreakpoint;
+#else
+
+#include "cdbcomstub.h"
+
+#endif // Q_OS_WIN
+
#endif // CDBCOM_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef CDBCOMSTUB_H
+#define CDBCOMSTUB_H
+
+// Stubs to make it partially compile for test purposes on non-Windows.
+
+// FIXME: Make everything more Windows-like instead of choosing arbitrary
+// values to make it compile.
+
+typedef unsigned long ULONG;
+typedef unsigned long long ULONG64;
+typedef void *PVOID;
+typedef unsigned short *PCWSTR;
+typedef void *HANDLE;
+typedef int HRESULT;
+typedef int DEBUG_VALUE;
+typedef int PDEBUG_BREAKPOINT2;
+const int MAX_PATH = 1024;
+
+inline bool FAILED(HRESULT) { return false; }
+
+enum
+{
+ DEBUG_OUTPUT_PROMPT_REGISTERS = 1,
+ DEBUG_OUTPUT_EXTENSION_WARNING = 2,
+ DEBUG_OUTPUT_WARNING = 4,
+ DEBUG_OUTPUT_ERROR = 8,
+ DEBUG_OUTPUT_DEBUGGEE = 16,
+ DEBUG_OUTPUT_DEBUGGEE_PROMPT = 32,
+ DEBUG_OUTPUT_PROMPT = 64,
+};
+
+#define IN
+#define OUT
+#define THIS
+#define THIS_
+#define REFIID void *
+#define THIS_
+#define STDMETHOD(x) HRESULT x
+#define STDMETHOD_(x, y) x y
+
+struct IUnknown
+{
+ virtual ~IUnknown();
+ virtual STDMETHOD_(ULONG, AddRef)(THIS) { return 1; }
+ virtual STDMETHOD_(ULONG, Release)(THIS) { return 1; }
+};
+
+struct IDebugOutputCallbacksWide : IUnknown
+{
+};
+
+struct CIDebugClient : IUnknown
+{
+};
+
+struct CIDebugControl : IUnknown
+{
+};
+
+struct CIDebugSystemObjects : IUnknown
+{
+};
+
+struct CIDebugSymbols : IUnknown
+{
+};
+
+struct CIDebugRegisters : IUnknown
+{
+ HRESULT GetNumberRegisters(ULONG *) const { return 0; }
+ HRESULT GetDescription(ULONG, char *, int, int, int) const { return 0; }
+ HRESULT GetValues(ULONG, int, int, DEBUG_VALUE *) const { return 0; }
+};
+
+struct CIDebugDataSpaces : IUnknown
+{
+};
+
+struct CIDebugSymbolGroup : IUnknown
+{
+};
+
+struct CIDebugBreakpoint : IUnknown
+{
+};
+
+enum DebugSymbolFlags
+{
+ DEBUG_SYMBOL_IS_LOCAL = 1,
+ DEBUG_SYMBOL_IS_ARGUMENT = 2,
+ DEBUG_SYMBOL_READ_ONLY = 4
+};
+
+struct DEBUG_SYMBOL_PARAMETERS
+{
+ DebugSymbolFlags Flags;
+ unsigned long ParentSymbol;
+};
+
+struct DEBUG_STACK_FRAME
+{
+};
+
+#endif // Q_OS_WIN
#include "cdboptionspage.h"
#include "cdboptions.h"
#include "cdbexceptionutils.h"
+#include "cdbsymbolpathlisteditor.h"
#include "debuggeragents.h"
#include "debuggeruiswitcher.h"
#include "debuggermainwindow.h"
#include "breakhandler.h"
#include "stackhandler.h"
#include "watchhandler.h"
+#include "threadshandler.h"
#include "registerhandler.h"
#include "moduleshandler.h"
#include "watchutils.h"
#include <utils/fancymainwindow.h>
#include <texteditor/itexteditor.h>
#include <utils/savedaction.h>
+#include <utils/checkablemessagebox.h>
#include <QtCore/QDebug>
#include <QtCore/QTimer>
// --- CdbDebugEnginePrivate
-CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *manager,
- const QSharedPointer<CdbOptions> &options,
- CdbDebugEngine* engine) :
+CdbDebugEnginePrivate::CdbDebugEnginePrivate(const QSharedPointer<CdbOptions> &options,
+ CdbDebugEngine *engine) :
m_options(options),
m_hDebuggeeProcess(0),
m_hDebuggeeThread(0),
m_breakEventMode(BreakEventHandle),
- m_dumper(new CdbDumperHelper(manager, this)),
+ m_dumper(new CdbDumperHelper(engine, this)),
m_currentThreadId(-1),
m_eventThreadId(-1),
m_interruptArticifialThreadId(-1),
if (!CdbCore::CoreEngine::init(m_options->path, errorMessage))
return false;
CdbDebugOutput *output = new CdbDebugOutput;
+ connect(output, SIGNAL(showMessage(QString,int,int)),
+ m_engine, SLOT(showMessage(QString,int,int)),
+ Qt::QueuedConnection); // Multithread invocation when loading dumpers.
setDebugOutput(DebugOutputBasePtr(output));
- connect(output, SIGNAL(debuggerOutput(int,QString)),
- manager(), SLOT(showDebuggerOutput(int,QString)));
- connect(output, SIGNAL(debuggerInputPrompt(int,QString)),
- manager(), SLOT(showDebuggerInput(int,QString)));
- connect(output, SIGNAL(debuggeeOutput(QString,bool)),
- manager(), SLOT(showApplicationOutput(QString,bool)));
- connect(output, SIGNAL(debuggeeInputPrompt(QString,bool)),
- manager(), SLOT(showApplicationOutput(QString,bool)));
-
setDebugEventCallback(DebugEventCallbackBasePtr(new CdbDebugEventCallback(m_engine)));
updateCodeLevel();
CdbDebugEngine::CdbDebugEngine(DebuggerManager *manager, const QSharedPointer<CdbOptions> &options) :
IDebuggerEngine(manager),
- m_d(new CdbDebugEnginePrivate(manager, options, this))
+ m_d(new CdbDebugEnginePrivate(options, this))
{
m_d->m_consoleStubProc.setMode(Utils::ConsoleProcess::Suspend);
connect(&m_d->m_consoleStubProc, SIGNAL(processMessage(QString,bool)),
}
// Compare
const double minVersion = 6.11;
- manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Version: %1").arg(version));
+ m_engine->showMessage(CdbDebugEngine::tr("Version: %1").arg(version));
if (version.toDouble() < minVersion) {
const QString msg = CdbDebugEngine::tr(
"<html>The installed version of the <i>Debugging Tools for Windows</i> (%1) "
}
}
-void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp)
+void CdbDebugEngine::startupChecks()
{
+ // Check symbol server unless the user has an external/internal setup
+ if (!qgetenv("_NT_SYMBOL_PATH").isEmpty()
+ || CdbOptions::indexOfSymbolServerPath(m_d->m_options->symbolPaths) != -1)
+ return;
+ // Prompt to use Symbol server unless the user checked "No nagging".
+ Core::ICore *core = Core::ICore::instance();
+ const QString nagSymbolServerKey = CdbOptions::settingsGroup() + QLatin1String("/NoPromptSymbolServer");
+ bool noFurtherNagging = core->settings()->value(nagSymbolServerKey, false).toBool();
+ if (noFurtherNagging)
+ return;
+
+ const QString symServUrl = QLatin1String("http://support.microsoft.com/kb/311503");
+ const QString msg = tr("<html><head/><body><p>The debugger is not configured to use the public "
+ "<a href=\"%1\">Microsoft Symbol Server</a>. This is recommended "
+ "for retrieval of the symbols of the operating system libraries.</p>"
+ "<p><i>Note:</i> A fast internet connection is required for this to work smoothly. Also, a delay "
+ "might occur when connecting for the first time.</p>"
+ "<p>Would you like to set it up?</p></br>"
+ "</body></html>").arg(symServUrl);
+ const QDialogButtonBox::StandardButton answer =
+ Utils::CheckableMessageBox::question(core->mainWindow(), tr("Symbol Server"), msg,
+ tr("Do not ask again"), &noFurtherNagging);
+ core->settings()->setValue(nagSymbolServerKey, noFurtherNagging);
+ if (answer == QDialogButtonBox::No)
+ return;
+ // Prompt for path and add it. Synchronize QSetting and debugger.
+ const QString cacheDir = CdbSymbolPathListEditor::promptCacheDirectory(core->mainWindow());
+ if (cacheDir.isEmpty())
+ return;
+ m_d->m_options->symbolPaths.push_back(CdbOptions::symbolServerPath(cacheDir));
+ m_d->m_options->toSettings(core->settings());
+ syncDebuggerPaths();
+}
+
+void CdbDebugEngine::startDebugger()
+{
+ QTC_ASSERT(runControl(), return);
+ const DebuggerStartParameters &sp = runControl()->sp();
if (debugCDBExecution)
- qDebug() << "startDebugger" << *sp;
+ qDebug() << "startDebugger";
CdbCore::BreakPoint::clearNormalizeFileNameCache();
+ startupChecks();
setState(AdapterStarting, Q_FUNC_INFO, __LINE__);
m_d->checkVersion();
if (m_d->m_hDebuggeeProcess) {
emit startFailed();
return;
}
- switch (sp->startMode) {
+ switch (sp.startMode) {
case AttachCore:
- case StartRemote:
+ case AttachToRemote:
warning(QLatin1String("Internal error: Mode not supported."));
setState(AdapterStartFailed, Q_FUNC_INFO, __LINE__);
emit startFailed();
default:
break;
}
- m_d->m_mode = sp->startMode;
+ m_d->m_mode = sp.startMode;
m_d->clearDisplay();
m_d->m_inferiorStartupComplete = false;
setState(AdapterStarted, Q_FUNC_INFO, __LINE__);
-
+ // Options
+ QString errorMessage;
+ if (!m_d->setBreakOnThrow(theDebuggerBoolSetting(BreakOnThrow), &errorMessage))
+ showMessage(errorMessage, LogWarning);
m_d->setVerboseSymbolLoading(m_d->m_options->verboseSymbolLoading);
// Figure out dumper. @TODO: same in gdb...
const QString dumperLibName = QDir::toNativeSeparators(manager()->qtDumperLibraryName());
setState(InferiorStarting, Q_FUNC_INFO, __LINE__);
manager()->showStatusMessage("Starting Debugger", messageTimeOut);
- QString errorMessage;
bool rc = false;
bool needWatchTimer = false;
m_d->clearForRun();
switch (m_d->m_mode) {
case AttachExternal:
case AttachCrashedExternal:
- rc = startAttachDebugger(sp->attachPID, m_d->m_mode, &errorMessage);
+ rc = startAttachDebugger(sp.attachPID, m_d->m_mode, &errorMessage);
needWatchTimer = true; // Fetch away module load, etc. even if crashed
break;
case StartInternal:
case StartExternal:
- if (sp->useTerminal) {
+ if (sp.useTerminal) {
// Attaching to console processes triggers an initial breakpoint, which we do not want
m_d->m_ignoreInitialBreakPoint = true;
// Launch console stub and wait for its startup
m_d->m_consoleStubProc.stop(); // We leave the console open, so recycle it now.
- m_d->m_consoleStubProc.setWorkingDirectory(sp->workingDir);
- m_d->m_consoleStubProc.setEnvironment(sp->environment);
- rc = m_d->m_consoleStubProc.start(sp->executable, sp->processArgs);
+ m_d->m_consoleStubProc.setWorkingDirectory(sp.workingDirectory);
+ m_d->m_consoleStubProc.setEnvironment(sp.environment);
+ rc = m_d->m_consoleStubProc.start(sp.executable, sp.processArgs);
if (!rc)
- errorMessage = tr("The console stub process was unable to start '%1'.").arg(sp->executable);
+ errorMessage = tr("The console stub process was unable to start '%1'.").arg(sp.executable);
// continues in slotConsoleStubStarted()...
} else {
needWatchTimer = true;
- rc = m_d->startDebuggerWithExecutable(sp->workingDir,
- sp->executable,
- sp->processArgs,
- sp->environment,
+ rc = m_d->startDebuggerWithExecutable(sp.workingDirectory,
+ sp.executable,
+ sp.processArgs,
+ sp.environment,
&errorMessage);
}
break;
// the exception to be delivered to the debugger
// Also, see special handling in slotModulesLoaded().
if (m_mode == AttachCrashedExternal) {
- const QString crashParameter = manager()->startParameters()->crashParameter;
+ const QString crashParameter = manager()->runControl()->sp().crashParameter;
if (!crashParameter.isEmpty()) {
ULONG64 evtNr = crashParameter.toULongLong();
const HRESULT hr = interfaces().debugControl->SetNotifyEventHandle(evtNr);
void CdbDebugEngine::processTerminated(unsigned long exitCode)
{
- manager()->showDebuggerOutput(LogMisc, tr("The process exited with exit code %1.").arg(exitCode));
+ showMessage(tr("The process exited with exit code %1.").arg(exitCode));
if (state() != InferiorStopping)
setState(InferiorStopping, Q_FUNC_INFO, __LINE__);
setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
// Need a stopped debuggee to act
if (!endInferior(action, &errorMessage)) {
errorMessage = QString::fromLatin1("Unable to detach from/end the debuggee: %1").arg(errorMessage);
- manager()->showDebuggerOutput(LogError, errorMessage);
+ m_engine->showMessage(errorMessage, LogError);
}
errorMessage.clear();
}
m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__);
if (!endedCleanly) {
errorMessage = QString::fromLatin1("There were errors trying to end debugging:\n%1").arg(errorMessage);
- manager()->showDebuggerOutput(LogError, errorMessage);
+ m_engine->showMessage(errorMessage, LogError);
}
}
clearForRun();
updateCodeLevel(); // Step by instruction
m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
- manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Continuing with '%1'...").arg(command));
+ m_engine->showMessage(CdbDebugEngine::tr("Continuing with '%1'...").arg(command));
QString errorMessage;
const bool success = executeDebuggerCommand(command, &errorMessage);
if (success) {
str << "gu";
break;
}
- manager()->showDebuggerOutput(tr("Stepping %1").arg(command));
+ showMessage(tr("Stepping %1").arg(command));
const HRESULT hr = m_d->interfaces().debugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, command.toLatin1().constData(), DEBUG_EXECUTE_ECHO);
success = SUCCEEDED(hr);
if (!success)
// Force a break when attaching to crashed process (if Creator was not spawned
// from handler).
if (state() != InferiorStopped) {
- manager()->showDebuggerOutput(LogMisc, QLatin1String("Forcing break..."));
+ showMessage(QLatin1String("Forcing break..."));
m_d->m_dumper->disable();
interruptInferior();
}
void CdbDebugEngine::executeRunToLine(const QString &fileName, int lineNumber)
{
- manager()->showDebuggerOutput(LogMisc, tr("Running up to %1:%2...").arg(fileName).arg(lineNumber));
+ showMessage(tr("Running up to %1:%2...").arg(fileName).arg(lineNumber));
QString errorMessage;
CdbCore::BreakPoint tempBreakPoint;
tempBreakPoint.fileName = fileName;
void CdbDebugEngine::executeRunToFunction(const QString &functionName)
{
- manager()->showDebuggerOutput(LogMisc, tr("Running up to function '%1()'...").arg(functionName));
+ showMessage(tr("Running up to function '%1()'...").arg(functionName));
QString errorMessage;
CdbCore::BreakPoint tempBreakPoint;
tempBreakPoint.funcName = functionName;
qDebug() << Q_FUNC_INFO;
}
-QList<Symbol> CdbDebugEngine::moduleSymbols(const QString &moduleName)
+void CdbDebugEngine::requestModuleSymbols(const QString &moduleName)
{
QList<Symbol> rc;
QString errorMessage;
} while (false);
if (!success)
warning(errorMessage);
- return rc;
+ manager()->showModuleSymbols(moduleName, rc);
}
void CdbDebugEngine::reloadRegisters()
exitDebugger();
}
-void CdbDebugEngine::warning(const QString &w)
+void CdbDebugEngine::warning(const QString &msg)
{
- manager()->showDebuggerOutput(LogWarning, w);
- qWarning("%s\n", qPrintable(w));
+ showMessage(msg, LogWarning);
+ qWarning("%s\n", qPrintable(msg));
}
void CdbDebugEnginePrivate::notifyException(long code, bool fatal, const QString &message)
break;
case EXCEPTION_BREAKPOINT:
if (m_ignoreInitialBreakPoint && !m_inferiorStartupComplete && m_breakEventMode == BreakEventHandle) {
- manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Ignoring initial breakpoint..."));
+ m_engine->showMessage(CdbDebugEngine::tr("Ignoring initial breakpoint..."));
m_breakEventMode = BreakEventIgnoreOnce;
}
break;
const QString msg = m_interrupted ?
CdbDebugEngine::tr("Interrupted in thread %1, current thread: %2").arg(m_interruptArticifialThreadId).arg(m_currentThreadId) :
CdbDebugEngine::tr("Stopped, current thread: %1").arg(m_currentThreadId);
- manager()->showDebuggerOutput(LogMisc, msg);
+ m_engine->showMessage(msg);
const int threadIndex = threadIndexById(threadsHandler, m_currentThreadId);
if (threadIndex != -1)
threadsHandler->setCurrentThread(threadIndex);
expression.clear();
}
if (!expression.isEmpty())
- m_stoppedMessage = CdbDebugEngine::tr("Breakpoint: %1").arg(expression);
+ m_stoppedMessage = breakpoint.type == CdbCore::BreakPoint::Code ?
+ CdbDebugEngine::tr("Breakpoint: %1").arg(expression) :
+ CdbDebugEngine::tr("Watchpoint: %1").arg(expression);
}
void CdbDebugEngine::reloadSourceFiles()
unsigned CdbDebugEngine::debuggerCapabilities() const
{
- return DisassemblerCapability | RegisterCapability | ShowMemoryCapability;
+ return DisassemblerCapability | RegisterCapability | ShowMemoryCapability
+ |WatchpointCapability
+ |BreakOnThrowAndCatchCapability; // Sort-of: Can break on throw().
}
// Accessed by DebuggerManager
virtual void shutdown();
virtual void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos);
- virtual void startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters);
+ virtual void startDebugger();
virtual void exitDebugger();
virtual void detachDebugger();
virtual void updateWatchData(const WatchData &data);
virtual void reloadModules();
virtual void loadSymbols(const QString &moduleName);
virtual void loadAllSymbols();
- virtual QList<Symbol> moduleSymbols(const QString &moduleName);
+ virtual void requestModuleSymbols(const QString &moduleName);
virtual void reloadRegisters();
virtual void reloadSourceFiles();
void warning(const QString &w);
private:
+ void startupChecks();
void setState(DebuggerState state, const char *func, int line);
inline bool startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage);
void processTerminated(unsigned long exitCode);
StoppedOther
};
- explicit CdbDebugEnginePrivate(DebuggerManager *parent,
- const QSharedPointer<CdbOptions> &options,
+ explicit CdbDebugEnginePrivate(const QSharedPointer<CdbOptions> &options,
CdbDebugEngine* engine);
~CdbDebugEnginePrivate();
bool init(QString *errorMessage);
const bool fatal = isFatalException(Exception->ExceptionCode);
if (debugCDB)
qDebug() << Q_FUNC_INFO << "\nex=" << Exception->ExceptionCode << " fatal=" << fatal << msg;
- m_pEngine->manager()->showApplicationOutput(msg, true);
- m_pEngine->manager()->showDebuggerOutput(LogMisc, msg);
+ m_pEngine->showMessage(msg, AppError);
+ m_pEngine->showMessage(msg, LogMisc);
m_pEngine->m_d->notifyException(Exception->ExceptionCode, fatal, msg);
return S_OK;
}
// -----------ExceptionLoggerEventCallback
CdbExceptionLoggerEventCallback::CdbExceptionLoggerEventCallback(int logChannel,
- bool skipNonFatalExceptions,
- DebuggerManager *manager) :
+ bool skipNonFatalExceptions, CdbDebugEngine *engine) :
m_logChannel(logChannel),
m_skipNonFatalExceptions(skipNonFatalExceptions),
- m_manager(manager)
+ m_engine(engine)
{
}
)
{
const bool recordException = !m_skipNonFatalExceptions || isFatalException(Exception->ExceptionCode);
- QString message;
- formatException(Exception, QTextStream(&message));
+ QString msg;
+ formatException(Exception, QTextStream(&msg));
if (recordException) {
m_exceptionCodes.push_back(Exception->ExceptionCode);
- m_exceptionMessages.push_back(message);
+ m_exceptionMessages.push_back(msg);
}
if (debugCDB)
- qDebug() << Q_FUNC_INFO << '\n' << message;
- m_manager->showDebuggerOutput(m_logChannel, message);
+ qDebug() << Q_FUNC_INFO << '\n' << msg;
+ m_engine->showMessage(msg, m_logChannel);
if (recordException)
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
return S_OK;
#include <QtCore/QStringList>
namespace Debugger {
-class DebuggerManager;
-
namespace Internal {
class CdbDebugEngine;
public:
CdbExceptionLoggerEventCallback(int logChannel,
bool skipNonFatalExceptions,
- DebuggerManager *access);
+ CdbDebugEngine *engine);
STDMETHOD(GetInterestMask)(
THIS_
private:
const int m_logChannel;
const bool m_skipNonFatalExceptions;
- DebuggerManager *m_manager;
+ CdbDebugEngine *m_engine;
QList<ULONG> m_exceptionCodes;
QStringList m_exceptionMessages;
};
**************************************************************************/
#include "cdbdebugoutput.h"
-#include "cdbdebugengine.h"
+#include "debuggerrunner.h"
#include "cdbdebugengine_p.h"
-
-#include <windows.h>
-#include <inc/dbgeng.h>
+#include "cdbcom.h"
namespace Debugger {
namespace Internal {
return LogWarning;
if (mask & (DEBUG_OUTPUT_ERROR))
return LogError;
- return LogMisc;
-}
-
-enum OutputKind { DebuggerOutput, DebuggerPromptOutput, DebuggeeOutput, DebuggeePromptOutput };
-
-static inline OutputKind outputKind(ULONG mask)
-{
if (mask & DEBUG_OUTPUT_DEBUGGEE)
- return DebuggeeOutput;
+ //return DebuggeeOutput;
+ return AppOutput;
if (mask & DEBUG_OUTPUT_DEBUGGEE_PROMPT)
- return DebuggeePromptOutput;
+ //return DebuggeePromptOutput;
+ return AppError;
if (mask & DEBUG_OUTPUT_PROMPT)
- return DebuggerPromptOutput;
- return DebuggerOutput;
+ //return DebuggerPromptOutput;
+ return AppError;
+ return LogMisc;
}
CdbDebugOutput::CdbDebugOutput()
{
if (debugCDB > 1)
qDebug() << Q_FUNC_INFO << "\n " << msg;
-
- switch (outputKind(mask)) {
- case DebuggerOutput:
- debuggerOutput(logChannel(mask), msg);
- break;
- case DebuggerPromptOutput:
- emit debuggerInputPrompt(logChannel(mask), msg);
- break;
- case DebuggeeOutput:
- emit debuggeeOutput(msg, true);
- break;
- case DebuggeePromptOutput:
- emit debuggeeInputPrompt(msg, false);
- break;
- }
+ emit showMessage(msg, logChannel(mask), -1);
}
} // namespace Internal
public:
CdbDebugOutput();
+signals:
+ void showMessage(const QString &output, int channel, int timeout);
+
protected:
virtual void output(ULONG mask, const QString &message);
-
-signals:
- void debuggerOutput(int channel, const QString &message);
- void debuggerInputPrompt(int channel, const QString &message);
- void debuggeeOutput(const QString &message, bool onStderr);
- void debuggeeInputPrompt(const QString &message, bool onStderr);
};
} // namespace Internal
#include "cdbdumperhelper.h"
#include "cdbmodules.h"
+#include "cdbdebugengine.h"
#include "cdbdebugengine_p.h"
#include "cdbdebugoutput.h"
#include "cdbdebugeventcallback.h"
// the QtCored4.pdb file to be present as we need "qstrdup"
// as dummy symbol. This is ok ATM since dumpers only
// make sense for Qt apps.
-static bool debuggeeLoadLibrary(DebuggerManager *manager,
+static bool debuggeeLoadLibrary(CdbDebugEngine *manager,
CdbCore::CoreEngine *engine,
unsigned long threadId,
const QString &moduleName,
virtual void run();
signals:
- void logMessage(int channel, const QString &m);
+ void logMessage(const QString &m, int channel);
void statusMessage(const QString &m, int timeOut);
private:
QApplication::setOverrideCursor(Qt::BusyCursor);
CdbDumperInitThread thread(h, errorMessage);
connect(&thread, SIGNAL(statusMessage(QString,int)),
- h.m_manager, SLOT(showStatusMessage(QString,int)),
+ h.m_engine, SLOT(showStatusMessage(QString,int)),
Qt::QueuedConnection);
- connect(&thread, SIGNAL(logMessage(int,QString)),
- h.m_manager, SLOT(showDebuggerOutput(int,QString)),
+ connect(&thread, SIGNAL(logMessage(QString,int)),
+ h.m_engine, SLOT(showMessage(QString,int)),
Qt::QueuedConnection);
QEventLoop eventLoop;
connect(&thread, SIGNAL(finished()), &eventLoop, SLOT(quit()), Qt::QueuedConnection);
eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
QApplication::restoreOverrideCursor();
if (thread.m_ok) {
- h.m_manager->showStatusMessage(QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "Stopped / Custom dumper library initialized."), messageTimeOut);
- h.m_manager->showDebuggerOutput(LogMisc, h.m_helper.toString());
+ h.m_engine->showStatusMessage(QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "Stopped / Custom dumper library initialized."), messageTimeOut);
+ h.m_engine->showMessage(h.m_helper.toString());
h.m_state = CdbDumperHelper::Initialized;
} else {
h.m_state = CdbDumperHelper::Disabled; // No message here
*errorMessage = QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "The custom dumper library could not be initialized: %1").arg(*errorMessage);
- h.m_manager->showStatusMessage(*errorMessage, messageTimeOut);
- h.m_manager->showQtDumperLibraryWarning(*errorMessage);
+ h.m_engine->showStatusMessage(*errorMessage, messageTimeOut);
+ h.m_engine->manager()->showQtDumperLibraryWarning(*errorMessage);
}
if (loadDebug)
qDebug() << Q_FUNC_INFO << '\n' << thread.m_ok;
switch (m_helper.initCallLoad(m_errorMessage)) {
case CdbDumperHelper::CallLoadOk:
case CdbDumperHelper::CallLoadAlreadyLoaded:
- emit logMessage(LogMisc, msgLoadSucceeded(m_helper.m_library, false));
+ emit logMessage(msgLoadSucceeded(m_helper.m_library, false), LogMisc);
m_helper.m_state = CdbDumperHelper::Loaded;
break;
case CdbDumperHelper::CallLoadError:
m_ok = false;
return;
case CdbDumperHelper::CallLoadNoQtApp:
- emit logMessage(LogMisc, QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "The debuggee does not appear to be Qt application."));
+ emit logMessage(QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "The debuggee does not appear to be Qt application."), LogMisc);
m_helper.m_state = CdbDumperHelper::Disabled; // No message here
m_ok = true;
return;
// ------------------- CdbDumperHelper
-CdbDumperHelper::CdbDumperHelper(DebuggerManager *manager,
+CdbDumperHelper::CdbDumperHelper(CdbDebugEngine *engine,
CdbCore::CoreEngine *coreEngine) :
m_tryInjectLoad(true),
m_msgDisabled(QLatin1String("Dumpers are disabled")),
m_msgNotInScope(QLatin1String("Data not in scope")),
m_state(NotLoaded),
- m_manager(manager),
+ m_engine(engine),
m_coreEngine(coreEngine),
m_inBufferAddress(0),
m_inBufferSize(0),
{
if (loadDebug)
qDebug() << Q_FUNC_INFO;
- m_manager->showDebuggerOutput(LogMisc, QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "Disabling dumpers due to debuggee crash..."));
+ m_engine->showMessage(QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "Disabling dumpers due to debuggee crash..."));
m_state = Disabled;
}
// for the thread to finish as this would lock up.
if (m_tryInjectLoad && module.contains(QLatin1String("Qt"), Qt::CaseInsensitive)) {
// Also shows up in the log window.
- m_manager->showStatusMessage(msgLoading(m_library, true), messageTimeOut);
+ m_engine->showMessage(msgLoading(m_library, true), StatusBar, messageTimeOut);
QString errorMessage;
SharedLibraryInjector sh(GetProcessId(debuggeeHandle));
if (sh.remoteInject(m_library, false, &errorMessage)) {
} else {
m_state = InjectLoadFailed;
// Ok, try call loading...
- m_manager->showDebuggerOutput(LogMisc, msgLoadFailed(m_library, true, errorMessage));
+ m_engine->showMessage(msgLoadFailed(m_library, true, errorMessage));
}
}
break;
// check if gdbmacros.dll loaded
if (module.contains(QLatin1String(dumperModuleNameC), Qt::CaseInsensitive)) {
m_state = Loaded;
- m_manager->showDebuggerOutput(LogMisc, msgLoadSucceeded(m_library, true));
+ m_engine->showMessage(msgLoadSucceeded(m_library, true));
}
break;
}
if (modules.filter(QLatin1String(qtCoreModuleNameC), Qt::CaseInsensitive).isEmpty())
return CallLoadNoQtApp;
// Try to load
- if (!debuggeeLoadLibrary(m_manager, m_coreEngine, m_dumperCallThread, m_library, errorMessage))
+ if (!debuggeeLoadLibrary(m_engine, m_coreEngine, m_dumperCallThread, m_library, errorMessage))
return CallLoadError;
return CallLoadOk;
}
{
*outDataPtr = 0;
// Skip stray startup-complete trap exceptions.
- QSharedPointer<CdbExceptionLoggerEventCallback> exLogger(new CdbExceptionLoggerEventCallback(LogWarning, true, m_manager));
+ QSharedPointer<CdbExceptionLoggerEventCallback> exLogger(new
+CdbExceptionLoggerEventCallback(LogWarning, true, m_engine));
CdbCore::EventCallbackRedirector eventRedir(m_coreEngine, exLogger);
Q_UNUSED(eventRedir)
// write input buffer
// Ensure types are parsed and known.
if (!CdbDumperInitThread::ensureDumperInitialized(*this, errorMessage)) {
*errorMessage = msgDumpFailed(wd, errorMessage);
- m_manager->showDebuggerOutput(LogError, *errorMessage);
+ m_engine->showMessage(*errorMessage, LogError);
return DumpError;
}
const QString message = QCoreApplication::translate("Debugger::Internal::CdbDumperHelper",
"Querying dumpers for '%1'/'%2' (%3)").
arg(QString::fromLatin1(wd.iname), wd.exp, wd.type);
- m_manager->showDebuggerOutput(LogMisc, message);
+ m_engine->showMessage(message);
const DumpExecuteResult der = executeDump(wd, td, dumpChildren, result, errorMessage);
if (der == DumpExecuteOk)
}
// log error
*errorMessage = msgDumpFailed(wd, errorMessage);
- m_manager->showDebuggerOutput(LogWarning, *errorMessage);
+ m_engine->showMessage(*errorMessage, LogWarning);
return DumpError;
}
namespace Internal {
class CdbDumperInitThread;
+class CdbDebugEngine;
/* For code clarity, all the stuff related to custom dumpers goes here.
* "Custom dumper" is a library compiled against the current
Initialized, // List of types, etc. retrieved
};
- explicit CdbDumperHelper(DebuggerManager *manager,
+ explicit CdbDumperHelper(CdbDebugEngine *engine,
CdbCore::CoreEngine *coreEngine);
~CdbDumperHelper();
const QString m_msgDisabled;
const QString m_msgNotInScope;
State m_state;
- DebuggerManager *m_manager;
+ CdbDebugEngine *m_engine;
CdbCore::CoreEngine *m_coreEngine;
QString m_library;
{
}
+QString CdbOptions::settingsGroup()
+{
+ return QLatin1String(settingsGroupC);
+}
+
void CdbOptions::clear()
{
enabled = false;
return rc;
}
+static const char symbolServerPrefixC[] = "symsrv*symsrv.dll*";
+static const char symbolServerPostfixC[] = "*http://msdl.microsoft.com/download/symbols";
+
+QString CdbOptions::symbolServerPath(const QString &cacheDir)
+{
+ QString s = QLatin1String(symbolServerPrefixC);
+ s += QDir::toNativeSeparators(cacheDir);
+ s += QLatin1String(symbolServerPostfixC);
+ return s;
+}
+
+bool CdbOptions::isSymbolServerPath(const QString &path, QString *cacheDir /* = 0 */)
+{
+ // Split apart symbol server post/prefixes
+ if (!path.startsWith(QLatin1String(symbolServerPrefixC)) || !path.endsWith(QLatin1String(symbolServerPostfixC)))
+ return false;
+ if (cacheDir) {
+ const unsigned prefixLength = qstrlen(symbolServerPrefixC);
+ *cacheDir = path.mid(prefixLength, path.size() - prefixLength - qstrlen(symbolServerPostfixC));
+ }
+ return true;
+}
+
+int CdbOptions::indexOfSymbolServerPath(const QStringList &paths, QString *cacheDir /* = 0 */)
+{
+ const int count = paths.size();
+ for (int i = 0; i < count; i++)
+ if (CdbOptions::isSymbolServerPath(paths.at(i), cacheDir))
+ return i;
+ return -1;
+}
+
} // namespace Internal
} // namespace Debugger
SymbolOptionsChanged = 0x4 };
unsigned compare(const CdbOptions &s) const;
+ // Format a symbol server specification with a cache directory
+ static QString symbolServerPath(const QString &cacheDir);
+ // Check whether the path is a symbol server specification and return the cache directory
+ static bool isSymbolServerPath(const QString &symbolPath, QString *cacheDir = 0);
+ static int indexOfSymbolServerPath(const QStringList &symbolPaths, QString *cacheDir = 0);
+
+ static QString settingsGroup();
+
bool enabled;
QString path;
QStringList symbolPaths;
#include "cdbdebugengine_p.h"
#include "debuggeractions.h"
#include "watchutils.h"
+#include "threadshandler.h"
#include <utils/savedaction.h>
const CdbCore::StackFrame &coreFrame = it.value();
data.address = coreFrame.address;
data.function = coreFrame.function;
- data.line = coreFrame.line;
+ data.lineNumber = coreFrame.line;
// Basename only for brevity
const int slashPos = coreFrame.fileName.lastIndexOf(slash);
- data.file = slashPos == -1 ? coreFrame.fileName : coreFrame.fileName.mid(slashPos + 1);
+ data.fileName = slashPos == -1 ? coreFrame.fileName : coreFrame.fileName.mid(slashPos + 1);
threads->push_back(data);
}
return true;
**************************************************************************/
#include "cdbsymbolpathlisteditor.h"
+#include "cdboptions.h"
+#include <utils/pathchooser.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
#include <QtGui/QFileDialog>
#include <QtGui/QAction>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QFormLayout>
+#include <QtGui/QMessageBox>
namespace Debugger {
namespace Internal {
+CacheDirectoryDialog::CacheDirectoryDialog(QWidget *parent) :
+ QDialog(parent), m_chooser(new Utils::PathChooser),
+ m_buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel))
+{
+ setWindowTitle(tr("Select Local Cache Folder"));
+ setModal(true);
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ QFormLayout *formLayout = new QFormLayout;
+ m_chooser->setExpectedKind(Utils::PathChooser::Directory);
+ m_chooser->setMinimumWidth(400);
+ formLayout->addRow(tr("Path:"), m_chooser);
+
+ QVBoxLayout *mainLayout = new QVBoxLayout;
+ mainLayout->addLayout(formLayout);
+ mainLayout->addWidget(m_buttonBox);
+
+ setLayout(mainLayout);
+
+ connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+}
+
+void CacheDirectoryDialog::setPath(const QString &p)
+{
+ m_chooser->setPath(p);
+}
+
+QString CacheDirectoryDialog::path() const
+{
+ return m_chooser->path();
+}
+
+void CacheDirectoryDialog::accept()
+{
+ // Ensure path exists
+ QString cache = path();
+ if (cache.isEmpty())
+ return;
+ QFileInfo fi(cache);
+ // Folder exists - all happy.
+ if (fi.isDir()) {
+ QDialog::accept();
+ return;
+ }
+ // Does a file of the same name exist?
+ if (fi.exists()) {
+ QMessageBox::warning(this, tr("Already Exists"),
+ tr("A file named '%1' already exists.").arg(cache));
+ return;
+ }
+ // Create
+ QDir root(QDir::root());
+ if (!root.mkpath(cache)) {
+ QMessageBox::warning(this, tr("Cannot Create"),
+ tr("The folder '%1' could not be created.").arg(cache));
+ return;
+ }
+ QDialog::accept();
+}
+
CdbSymbolPathListEditor::CdbSymbolPathListEditor(QWidget *parent) :
Utils::PathListEditor(parent)
{
"Requires specifying a local cache directory."));
}
+QString CdbSymbolPathListEditor::promptCacheDirectory(QWidget *parent)
+{
+ CacheDirectoryDialog dialog(parent);
+ dialog.setPath(QDir::tempPath() + QDir::separator() + QLatin1String("symbolcache"));
+ if (dialog.exec() != QDialog::Accepted)
+ return QString();
+ return dialog.path();
+}
+
void CdbSymbolPathListEditor::addSymbolServer()
{
- const QString title = tr("Pick a local cache directory");
- const QString cacheDir = QFileDialog::getExistingDirectory(this, title);
- if (!cacheDir.isEmpty()) {
- const QString path = QString::fromLatin1("symsrv*symsrv.dll*%1*http://msdl.microsoft.com/download/symbols").
- arg(QDir::toNativeSeparators(cacheDir));
- insertPathAtCursor(path);
- }
+ const QString cacheDir = promptCacheDirectory(this);
+ if (!cacheDir.isEmpty())
+ insertPathAtCursor(CdbOptions::symbolServerPath(cacheDir));
}
} // namespace Internal
#include <utils/pathlisteditor.h>
+#include <QtGui/QDialog>
+
+namespace Utils {
+ class PathChooser;
+}
+
+QT_BEGIN_NAMESPACE
+class QDialogButtonBox;
+QT_END_NAMESPACE
+
namespace Debugger {
namespace Internal {
+// Internal helper dialog prompting for a cache directory
+// using a PathChooser.
+// Note that QFileDialog does not offer a way of suggesting
+// a non-existent folder, which is in turn automatically
+// created. This is done here (suggest $TEMP\symbolcache
+// regardless of its existence).
+
+class CacheDirectoryDialog : public QDialog {
+ Q_OBJECT
+public:
+ explicit CacheDirectoryDialog(QWidget *parent = 0);
+
+ void setPath(const QString &p);
+ QString path() const;
+
+ virtual void accept();
+
+private:
+ Utils::PathChooser *m_chooser;
+ QDialogButtonBox *m_buttonBox;
+};
+
class CdbSymbolPathListEditor : public Utils::PathListEditor
{
Q_OBJECT
public:
explicit CdbSymbolPathListEditor(QWidget *parent = 0);
+ static QString promptCacheDirectory(QWidget *parent);
+
private slots:
void addSymbolServer();
};
m_debugEventCallback->setModuleCount(m);
}
+static inline const char *debugFilterDescription(ULONG in)
+{
+ switch (in) {
+ case DEBUG_FILTER_BREAK:
+ return "break";
+ case DEBUG_FILTER_SECOND_CHANCE_BREAK:
+ return "2nd-chance-break";
+ case DEBUG_FILTER_OUTPUT:
+ return "output";
+ case DEBUG_FILTER_IGNORE:
+ return "ignore";
+ default:
+ break;
+ }
+ return "unknown";
+}
+
+static inline QString msgCannotChangeExceptionCommands(unsigned long code, const QString &why)
+{
+ return QString::fromLatin1("Cannot change exception commands for 0x%1: %2").
+ arg(code, 0, 16).arg(why);
+}
+
+bool CoreEngine::setBreakOnThrow(bool b, QString *errorMessage)
+{
+ // See eventFilterStatus() for defaults
+ const unsigned long code = 0xe06d7363;
+ const unsigned long executionCommand = b ? DEBUG_FILTER_BREAK : DEBUG_FILTER_SECOND_CHANCE_BREAK;
+ const unsigned long continueCommand = b ? DEBUG_FILTER_BREAK : DEBUG_FILTER_SECOND_CHANCE_BREAK;
+ return setExceptionCommands(code, executionCommand, continueCommand, errorMessage);
+}
+
+bool CoreEngine::setExceptionCommands(ULONG code,
+ ULONG executionCommand,
+ ULONG continueCommand,
+ QString *errorMessage)
+{
+ DEBUG_EXCEPTION_FILTER_PARAMETERS exceptionParameters;
+ HRESULT hr = m_cif.debugControl->GetExceptionFilterParameters(1, &code, 0, &exceptionParameters);
+ if (FAILED(hr)) {
+ *errorMessage = msgCannotChangeExceptionCommands(code, msgComFailed("GetExceptionFilterParameters", hr));
+ return false;
+ }
+ if (exceptionParameters.ExecutionOption == executionCommand
+ && exceptionParameters.ContinueOption == continueCommand)
+ return true;
+ if (debug)
+ qDebug("Changing exception commands of 0x%x from %s/%s to %s/%s",
+ code,
+ debugFilterDescription(exceptionParameters.ExecutionOption),
+ debugFilterDescription(exceptionParameters.ContinueOption),
+ debugFilterDescription(executionCommand),
+ debugFilterDescription(continueCommand));
+
+ exceptionParameters.ExecutionOption = executionCommand;
+ exceptionParameters.ContinueOption = continueCommand;
+ hr = m_cif.debugControl->SetExceptionFilterParameters(1, &exceptionParameters);
+ if (FAILED(hr)) {
+ *errorMessage = msgCannotChangeExceptionCommands(code, msgComFailed("SetExceptionFilterParameters", hr));
+ return false;
+ }
+ return true;
+}
+
+static void formatEventFilter(CIDebugControl *ctl, unsigned long start, unsigned long end,
+ bool isException,
+ QTextStream &str)
+{
+ enum { bufSize =2048 };
+ WCHAR buffer[bufSize];
+ for (unsigned long i = start; i < end; i++) {
+ HRESULT hr = ctl->GetEventFilterTextWide(i, buffer, bufSize, 0);
+ if (SUCCEEDED(hr)) {
+ ULONG size;
+ str << "- #" << i << " \"" << QString::fromUtf16(buffer) << '"';
+ hr = ctl->GetEventFilterCommandWide(i, buffer, bufSize, &size);
+ if (SUCCEEDED(hr) && size > 1)
+ str << " command: '" << QString::fromUtf16(buffer) << '\'';
+ if (isException) {
+ DEBUG_EXCEPTION_FILTER_PARAMETERS exceptionParameters;
+ hr = ctl->GetExceptionFilterParameters(1, 0, i, &exceptionParameters);
+ if (SUCCEEDED(hr)) {
+ str.setIntegerBase(16);
+ str << " code: 0x" << exceptionParameters.ExceptionCode;
+ str.setIntegerBase(10);
+ str << " execute: '"
+ << debugFilterDescription(exceptionParameters.ExecutionOption)
+ << "' continue: '" << debugFilterDescription(exceptionParameters.ContinueOption)
+ << '\'';
+ if (exceptionParameters.SecondCommandSize) {
+ hr = ctl->GetExceptionFilterSecondCommandWide(i, buffer, bufSize, 0);
+ if (SUCCEEDED(hr))
+ str << " 2nd-command '" << QString::fromUtf16(buffer) << '\'';
+ }
+ }
+ } // isException
+ str << '\n';
+ }
+ }
+}
+
+QString CoreEngine::eventFilterStatus() const
+{
+ ULONG specificEvents, specificExceptions, arbitraryExceptions;
+ QString rc;
+ QTextStream str(&rc);
+
+ HRESULT hr = m_cif.debugControl->GetNumberEventFilters(&specificEvents, &specificExceptions, &arbitraryExceptions);
+ if (FAILED(hr))
+ return QString();
+ str << "Specific events\n";
+ formatEventFilter(m_cif.debugControl, 0, specificEvents, false, str);
+ const ULONG arbitraryExceptionsStart = specificEvents + specificExceptions;
+ str << "Specific exceptions\n";
+ formatEventFilter(m_cif.debugControl, specificEvents, arbitraryExceptionsStart, true, str);
+ str << "Arbitrary exceptions\n";
+ const ULONG arbitraryExceptionsEnd = arbitraryExceptionsStart + arbitraryExceptions;
+ formatEventFilter(m_cif.debugControl, arbitraryExceptionsStart, arbitraryExceptionsEnd, true, str);
+ return rc;
+}
+
// ------------- DEBUG_VALUE formatting helpers
// format an array of integers as "0x323, 0x2322, ..."
unsigned moduleCount() const;
+ bool setBreakOnThrow(bool b, QString *errorMessage);
+ bool setExceptionCommands(ULONG code,
+ ULONG executionCommand,
+ ULONG continueCommand,
+ QString *errorMessage);
+
+ QString eventFilterStatus() const;
+
signals:
void watchTimerDebugEvent();
namespace CdbCore {
StackFrame::StackFrame() :
- line(0),address(0)
+ line(0), address(0)
{
}
script
HEADERS += breakhandler.h \
breakwindow.h \
+ breakpoint.h \
debuggeragents.h \
debuggeractions.h \
debuggerconstants.h \
procinterrupt.h \
registerhandler.h \
registerwindow.h \
+ stackframe.h \
stackhandler.h \
stackwindow.h \
snapshothandler.h \
watchwindow.h \
name_demangler.h \
debuggeruiswitcher.h \
- debuggermainwindow.h
+ debuggermainwindow.h \
+ threadshandler.h
SOURCES += breakhandler.cpp \
breakwindow.cpp \
breakwindow.h \
watchutils.cpp \
name_demangler.cpp \
debuggeruiswitcher.cpp \
- debuggermainwindow.cpp
+ debuggermainwindow.cpp \
+ threadshandler.cpp \
+ stackframe.cpp
FORMS += attachexternaldialog.ui \
attachcoredialog.ui \
+ attachtcfdialog.ui \
breakbyfunction.ui \
breakcondition.ui \
dumperoptionpage.ui \
include(gdb/gdb.pri)
include(script/script.pri)
include(pdb/pdb.pri)
+include(qml/qml.pri)
+include(tcf/tcf.pri)
include(shared/shared.pri)
OTHER_FILES += Debugger.pluginspec
<file>images/debugger_stepoverproc_small.png</file>
<file>images/debugger_stop.png</file>
<file>images/debugger_stop_small.png</file>
+ <file>images/watchpoint.png</file>
<file>images/breakpoint_16.png</file>
<file>images/breakpoint_24.png</file>
<file>images/breakpoint_disabled_16.png</file>
QAction *breakAction;
QAction *sepAction;
QAction *reverseDirectionAction;
+ QAction *frameUpAction;
+ QAction *frameDownAction;
};
} // namespace Internal
if (it != d->cache.end()) {
QString msg = _("Use cache disassembler for '%1' in '%2'")
.arg(frame.function).arg(frame.file);
- d->manager->showDebuggerOutput(msg);
+ QTC_ASSERT(d->manager->runControl(), /**/);
+ if (d->manager->runControl())
+ d->manager->runControl()->showMessage(msg);
setContents(*it);
return;
}
StartExternal, // Start binary found in file system
AttachExternal, // Attach to running process by process id
AttachCrashedExternal, // Attach to crashed process by process id
+ AttachTcf, // Attach to a running Target Communication Framework agent
AttachCore, // Attach to a core file
- StartRemote // Start and attach to a remote process
+ AttachToRemote, // Start and attach to a remote process
+ StartRemoteGdb // Start gdb itself remotely
};
enum DebuggerCapabilities
BreakOnThrowAndCatchCapability = 0x200,
ReturnFromFunctionCapability = 0x400,
CreateFullBacktraceCapability = 0x800,
- AddWatcherCapability = 0x1000
+ AddWatcherCapability = 0x1000,
+ WatchpointCapability = 0x2000
};
enum LogChannel
{
LogInput, // Used for user input
+ LogMiscInput, // Used for misc stuff in the input pane
LogOutput,
LogWarning,
LogError,
LogStatus, // Used for status changed messages
LogTime, // Used for time stamp messages
LogDebug,
- LogMisc
+ LogMisc,
+ AppOutput,
+ AppError,
+ StatusBar // LogStatus and also put to the status bar
};
} // namespace Debugger
#include "ui_attachcoredialog.h"
#include "ui_attachexternaldialog.h"
+#include "ui_attachtcfdialog.h"
#include "ui_startexternaldialog.h"
#include "ui_startremotedialog.h"
{
if (index.isValid()) {
const QModelIndex index0 = mapToSource(index);
- QModelIndex index = index0.sibling(index0.row(), 0);
- if (const QStandardItem *item = m_model->itemFromIndex(index))
+ QModelIndex siblingIndex = index0.sibling(index0.row(), 0);
+ if (const QStandardItem *item = m_model->itemFromIndex(siblingIndex))
return item->text();
}
return QString();
if (!psProcess.waitForStarted())
return rc;
QByteArray output;
- if (!Utils::SynchronousProcess::readDataFromProcess(psProcess, 30000, &output))
+ if (!Utils::SynchronousProcess::readDataFromProcess(psProcess, 30000, &output, 0, false))
return rc;
// Split "457 S+ /Users/foo.app"
const QStringList lines = QString::fromLocal8Bit(output).split(QLatin1Char('\n'));
///////////////////////////////////////////////////////////////////////
//
+// AttachTcfDialog
+//
+///////////////////////////////////////////////////////////////////////
+
+AttachTcfDialog::AttachTcfDialog(QWidget *parent)
+ : QDialog(parent),
+ m_ui(new Ui::AttachTcfDialog)
+{
+ m_ui->setupUi(this);
+ m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+ m_ui->serverStartScript->setExpectedKind(Utils::PathChooser::File);
+ m_ui->serverStartScript->setPromptDialogTitle(tr("Select Executable"));
+
+ connect(m_ui->useServerStartScriptCheckBox, SIGNAL(toggled(bool)),
+ this, SLOT(updateState()));
+
+ connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+ updateState();
+}
+
+AttachTcfDialog::~AttachTcfDialog()
+{
+ delete m_ui;
+}
+
+void AttachTcfDialog::setRemoteChannel(const QString &channel)
+{
+ m_ui->channelLineEdit->setText(channel);
+}
+
+QString AttachTcfDialog::remoteChannel() const
+{
+ return m_ui->channelLineEdit->text();
+}
+
+void AttachTcfDialog::setRemoteArchitectures(const QStringList &list)
+{
+ m_ui->architectureComboBox->clear();
+ if (!list.isEmpty()) {
+ m_ui->architectureComboBox->insertItems(0, list);
+ m_ui->architectureComboBox->setCurrentIndex(0);
+ }
+}
+
+void AttachTcfDialog::setRemoteArchitecture(const QString &arch)
+{
+ int index = m_ui->architectureComboBox->findText(arch);
+ if (index != -1)
+ m_ui->architectureComboBox->setCurrentIndex(index);
+}
+
+QString AttachTcfDialog::remoteArchitecture() const
+{
+ int index = m_ui->architectureComboBox->currentIndex();
+ return m_ui->architectureComboBox->itemText(index);
+}
+
+void AttachTcfDialog::setServerStartScript(const QString &scriptName)
+{
+ m_ui->serverStartScript->setPath(scriptName);
+}
+
+QString AttachTcfDialog::serverStartScript() const
+{
+ return m_ui->serverStartScript->path();
+}
+
+void AttachTcfDialog::setUseServerStartScript(bool on)
+{
+ m_ui->useServerStartScriptCheckBox->setChecked(on);
+}
+
+bool AttachTcfDialog::useServerStartScript() const
+{
+ return m_ui->useServerStartScriptCheckBox->isChecked();
+}
+
+void AttachTcfDialog::updateState()
+{
+ bool enabled = m_ui->useServerStartScriptCheckBox->isChecked();
+ m_ui->serverStartScriptLabel->setEnabled(enabled);
+ m_ui->serverStartScript->setEnabled(enabled);
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//
// StartExternalDialog
//
///////////////////////////////////////////////////////////////////////
m_ui->execFile->setExpectedKind(Utils::PathChooser::File);
m_ui->execFile->setPromptDialogTitle(tr("Select Executable"));
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+ m_ui->workingDirectory->setExpectedKind(Utils::PathChooser::Directory);
+ m_ui->workingDirectory->setPromptDialogTitle(tr("Select Working Directory"));
//execLabel->setHidden(false);
//execEdit->setHidden(false);
return m_ui->execFile->path();
}
+void StartExternalDialog::setWorkingDirectory(const QString &str)
+{
+ m_ui->workingDirectory->setPath(str);
+}
+
+QString StartExternalDialog::workingDirectory() const
+{
+ return m_ui->workingDirectory->path();
+}
+
void StartExternalDialog::setExecutableArguments(const QString &str)
{
m_ui->argsEdit->setText(str);
namespace Ui {
class AttachCoreDialog;
class AttachExternalDialog;
+class AttachTcfDialog;
class StartExternalDialog;
class StartRemoteDialog;
} // namespace Ui
ProcessListFilterModel *m_model;
};
+class AttachTcfDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit AttachTcfDialog(QWidget *parent);
+ ~AttachTcfDialog();
+
+ QString remoteChannel() const;
+ void setRemoteChannel(const QString &host);
+
+ QString remoteArchitecture() const;
+ void setRemoteArchitecture(const QString &arch);
+ void setRemoteArchitectures(const QStringList &arches);
+
+ QString serverStartScript() const;
+ bool useServerStartScript() const;
+ void setUseServerStartScript(bool on);
+ void setServerStartScript(const QString &scriptName);
+
+private slots:
+ void updateState();
+
+private:
+ Ui::AttachTcfDialog *m_ui;
+};
+
class StartExternalDialog : public QDialog
{
Q_OBJECT
explicit StartExternalDialog(QWidget *parent);
~StartExternalDialog();
+ QString executableFile() const;
void setExecutableFile(const QString &executable);
- void setExecutableArguments(const QString &args);
- QString executableFile() const;
QString executableArguments() const;
+ void setExecutableArguments(const QString &args);
+
+ QString workingDirectory() const;
+ void setWorkingDirectory(const QString &str);
+
bool breakAtMain() const;
private:
explicit StartRemoteDialog(QWidget *parent);
~StartRemoteDialog();
- void setRemoteChannel(const QString &host);
- void setRemoteArchitecture(const QString &arch);
- void setRemoteArchitectures(const QStringList &arches);
- void setLocalExecutable(const QString &executable);
- void setDebugger(const QString &debugger);
QString localExecutable() const;
+ void setLocalExecutable(const QString &executable);
+
QString remoteChannel() const;
+ void setRemoteChannel(const QString &host);
+
QString remoteArchitecture() const;
- void setServerStartScript(const QString &scriptName);
- QString serverStartScript() const;
- void setUseServerStartScript(bool on);
+ void setRemoteArchitecture(const QString &arch);
+ void setRemoteArchitectures(const QStringList &arches);
+
bool useServerStartScript() const;
- void setSysRoot(const QString &sysRoot);
+ void setUseServerStartScript(bool on);
+ QString serverStartScript() const;
+ void setServerStartScript(const QString &scriptName);
+
QString sysRoot() const;
+ void setSysRoot(const QString &sysRoot);
+
QString debugger() const;
+ void setDebugger(const QString &debugger);
private slots:
void updateState();
#include "debuggermanager.h"
-#include "debuggerplugin.h"
#include "debuggeractions.h"
#include "debuggeragents.h"
-#include "debuggerrunner.h"
#include "debuggerconstants.h"
-#include "idebuggerengine.h"
+#include "debuggermainwindow.h"
+#include "debuggerplugin.h"
+#include "debuggerrunner.h"
#include "debuggerstringutils.h"
-#include "watchutils.h"
+#include "debuggertooltip.h"
#include "debuggeruiswitcher.h"
-#include "debuggermainwindow.h"
+#include "idebuggerengine.h"
+#include "watchutils.h"
#include "breakwindow.h"
#include "debuggeroutputwindow.h"
#include "snapshothandler.h"
#include "stackhandler.h"
#include "stackframe.h"
+#include "threadshandler.h"
#include "watchhandler.h"
#include "debuggerdialogs.h"
#include <QtGui/QTextCursor>
#include <QtGui/QToolButton>
#include <QtGui/QToolTip>
+#include <QtGui/QTreeWidget>
#define DEBUG_STATE 1
#ifdef DEBUG_STATE
// use Q_FUNC_INFO?
# define STATE_DEBUG(s) \
do { QString msg; QTextStream ts(&msg); ts << s; \
- showDebuggerOutput(LogDebug, msg); } while (0)
+ showMessage(msg, LogDebug); } while (0)
#else
# define STATE_DEBUG(s)
#endif
IDebuggerEngine *createGdbEngine(DebuggerManager *parent);
IDebuggerEngine *createScriptEngine(DebuggerManager *parent);
IDebuggerEngine *createPdbEngine(DebuggerManager *parent);
+IDebuggerEngine *createTcfEngine(DebuggerManager *parent);
+IDebuggerEngine *createQmlEngine(DebuggerManager *parent);
// The createCdbEngine function takes a list of options pages it can add to.
// This allows for having a "enabled" toggle on the page independently
nospace << "executable=" << p.executable << " coreFile=" << p.coreFile
<< " processArgs=" << p.processArgs.join(sep)
<< " environment=<" << p.environment.size() << " variables>"
- << " workingDir=" << p.workingDir << " buildDir=" << p.buildDir
+ << " workingDir=" << p.workingDirectory
<< " attachPID=" << p.attachPID << " useTerminal=" << p.useTerminal
<< " remoteChannel=" << p.remoteChannel
<< " remoteArchitecture=" << p.remoteArchitecture
const char *DebuggerManager::stateName(int s)
{
- #define SN(x) case x: return #x;
+# define SN(x) case x: return #x;
switch (s) {
SN(DebuggerNotReady)
SN(EngineStarting)
SN(EngineShuttingDown)
}
return "<unknown>";
- #undef SN
+# undef SN
}
static Debugger::Internal::IDebuggerEngine *scriptEngine = 0;
static Debugger::Internal::IDebuggerEngine *cdbEngine = 0;
static Debugger::Internal::IDebuggerEngine *pdbEngine = 0;
+static Debugger::Internal::IDebuggerEngine *qmlEngine = 0;
+static Debugger::Internal::IDebuggerEngine *tcfEngine = 0;
struct DebuggerManagerPrivate
{
const QIcon m_locationMarkIcon;
// FIXME: Remove engine-specific state
- DebuggerStartParametersPtr m_startParameters;
+ const DebuggerRunControl *m_runControl;
qint64 m_inferiorPid;
/// Views
DebuggerManagerActions m_actions;
QWidget *m_breakWindow;
+ QWidget *m_returnWindow;
QWidget *m_localsWindow;
+ QWidget *m_watchersWindow;
QWidget *m_registerWindow;
QWidget *m_modulesWindow;
QWidget *m_snapshotWindow;
SourceFilesWindow *m_sourceFilesWindow;
QWidget *m_stackWindow;
QWidget *m_threadsWindow;
- QWidget *m_watchersWindow;
DebuggerOutputWindow *m_outputWindow;
bool m_busy;
m_stopIcon(QLatin1String(":/debugger/images/debugger_stop_small.png")),
m_interruptIcon(QLatin1String(":/debugger/images/debugger_interrupt_small.png")),
m_locationMarkIcon(QLatin1String(":/debugger/images/location_16.png")),
- m_startParameters(new DebuggerStartParameters),
m_inferiorPid(0),
m_disassemblerViewAgent(manager),
m_engine(0)
{
+ m_runControl = 0;
m_interruptIcon.addFile(":/debugger/images/debugger_interrupt.png");
m_stopIcon.addFile(":/debugger/images/debugger_stop.png");
}
DebuggerManager::~DebuggerManager()
{
- #define doDelete(ptr) delete ptr; ptr = 0
+# define doDelete(ptr) delete ptr; ptr = 0
doDelete(scriptEngine);
doDelete(pdbEngine);
doDelete(gdbEngine);
doDelete(cdbEngine);
+ doDelete(tcfEngine);
+ doDelete(qmlEngine);
doDelete(d->m_breakHandler);
doDelete(d->m_threadsHandler);
doDelete(d->m_snapshotHandler);
doDelete(d->m_stackHandler);
doDelete(d->m_watchHandler);
-
- doDelete(gdbEngine);
- doDelete(scriptEngine);
- doDelete(cdbEngine);
- #undef doDelete
+# undef doDelete
DebuggerManagerPrivate::instance = 0;
delete d;
}
d->m_sourceFilesWindow->setObjectName(QLatin1String("CppDebugSources"));
d->m_threadsWindow = new ThreadsWindow;
d->m_threadsWindow->setObjectName(QLatin1String("CppDebugThreads"));
+ d->m_returnWindow = new WatchWindow(WatchWindow::ReturnType, this);
+ d->m_returnWindow->setObjectName(QLatin1String("CppDebugReturn"));
d->m_localsWindow = new WatchWindow(WatchWindow::LocalsType, this);
d->m_localsWindow->setObjectName(QLatin1String("CppDebugLocals"));
d->m_watchersWindow = new WatchWindow(WatchWindow::WatchersType, this);
this, SLOT(loadAllSymbols()));
connect(modulesView, SIGNAL(fileOpenRequested(QString)),
this, SLOT(fileOpen(QString)));
- connect(modulesView, SIGNAL(newDockRequested(QWidget*)),
- this, SLOT(createNewDock(QWidget*)));
// Source Files
//d->m_sourceFilesHandler = new SourceFilesHandler;
d->m_registerHandler = new RegisterHandler;
registerView->setModel(d->m_registerHandler->model());
- // Locals
+
+ // Return Value
d->m_watchHandler = new WatchHandler(this);
+ QTreeView *returnView = qobject_cast<QTreeView *>(d->m_returnWindow);
+ returnView->setModel(d->m_watchHandler->model(ReturnWatch));
+
+ // Locals
QTreeView *localsView = qobject_cast<QTreeView *>(d->m_localsWindow);
localsView->setModel(d->m_watchHandler->model(LocalsWatch));
connect(localsView->header(), SIGNAL(sectionResized(int,int,int)),
this, SLOT(updateWatchersHeader(int,int,int)), Qt::QueuedConnection);
- // Log
- connect(this, SIGNAL(emitShowInput(int, QString)),
- d->m_outputWindow, SLOT(showInput(int, QString)), Qt::QueuedConnection);
- connect(this, SIGNAL(emitShowOutput(int, QString)),
- d->m_outputWindow, SLOT(showOutput(int, QString)), Qt::QueuedConnection);
-
// Tooltip
- //QTreeView *tooltipView = qobject_cast<QTreeView *>(d->m_tooltipWindow);
- //tooltipView->setModel(d->m_watchHandler->model(TooltipsWatch));
qRegisterMetaType<WatchData>("WatchData");
qRegisterMetaType<StackCookie>("StackCookie");
QIcon(":/debugger/images/debugger_reversemode_16.png"));
d->m_actions.reverseDirectionAction->setIconVisibleInMenu(false);
+ d->m_actions.frameDownAction =
+ new QAction(tr("Move to Called Frame"), this);
+ d->m_actions.frameUpAction =
+ new QAction(tr("Move to Calling Frame"), this);
+
+ d->m_actions.reverseDirectionAction->setCheckable(false);
connect(d->m_actions.continueAction, SIGNAL(triggered()),
this, SLOT(executeContinue()));
connect(d->m_actions.stopAction, SIGNAL(triggered()),
this, SLOT(addToWatchWindow()));
connect(d->m_actions.snapshotAction, SIGNAL(triggered()),
this, SLOT(makeSnapshot()));
+ connect(d->m_actions.frameDownAction, SIGNAL(triggered()),
+ this, SLOT(frameDown()));
+ connect(d->m_actions.frameUpAction, SIGNAL(triggered()),
+ this, SLOT(frameUp()));
connect(d->m_statusTimer, SIGNAL(timeout()),
this, SLOT(clearStatusMessage()));
localsAndWatchers->setObjectName(QLatin1String("CppDebugLocalsAndWatchers"));
localsAndWatchers->setWindowTitle(d->m_localsWindow->windowTitle());
localsAndWatchers->addWidget(d->m_localsWindow);
+ localsAndWatchers->addWidget(d->m_returnWindow);
localsAndWatchers->addWidget(d->m_watchersWindow);
//localsAndWatchers->addWidget(d->m_tooltipWindow);
localsAndWatchers->setStretchFactor(0, 3);
//pdbEngine->addOptionPages(&rc);
}
+ if (enabledTypeFlags & TcfEngineType) {
+ tcfEngine = createTcfEngine(this);
+ tcfEngine->addOptionPages(&rc);
+ }
+
+ if (enabledTypeFlags & QmlEngineType) {
+ qmlEngine = createQmlEngine(this);
+ //qmlEngine->addOptionPages(&rc);
+ }
+
d->m_engine = 0;
STATE_DEBUG(gdbEngine << cdbEngine << scriptEngine
<< pdbEngine << rc.size());
void DebuggerManager::showStatusMessage(const QString &msg0, int timeout)
{
Q_UNUSED(timeout)
- showDebuggerOutput(LogStatus, msg0);
+ showMessage(msg0, LogStatus);
QString msg = msg0;
msg.replace(QLatin1Char('\n'), QString());
d->m_statusLabel->setText(msg);
}
}
-void DebuggerManager::showApplicationOutput(const QString &str, bool onStdErr)
-{
- emit applicationOutputAvailable(str, onStdErr);
-}
-
void DebuggerManager::aboutToShutdown()
{
- STATE_DEBUG(d->m_engine);
+ // TODO: STATE_DEBUG(d->m_engine);
if (d->m_engine)
d->m_engine->shutdown();
d->m_engine = 0;
}
-void DebuggerManager::makeSnapshot()
+void DebuggerManager::frameUp()
{
QTC_ASSERT(d->m_engine, return);
- d->m_engine->makeSnapshot();
+ int currentIndex = stackHandler()->currentIndex();
+ activateFrame(qMin(currentIndex + 1, stackHandler()->stackSize() - 1));
}
-void DebuggerManager::activateSnapshot(int index)
+void DebuggerManager::frameDown()
{
QTC_ASSERT(d->m_engine, return);
- d->m_engine->activateSnapshot(index);
+ int currentIndex = stackHandler()->currentIndex();
+ activateFrame(qMax(currentIndex - 1, 0));
}
-void DebuggerManager::removeSnapshot(int index)
+void DebuggerManager::makeSnapshot()
{
QTC_ASSERT(d->m_engine, return);
- d->m_snapshotHandler->removeSnapshot(index);
+ d->m_engine->makeSnapshot();
}
-BreakpointData *DebuggerManager::findBreakpoint(const QString &fileName, int lineNumber)
+void DebuggerManager::activateSnapshot(int index)
{
- if (!d->m_breakHandler)
- return 0;
- int index = d->m_breakHandler->findBreakpoint(fileName, lineNumber);
- return index == -1 ? 0 : d->m_breakHandler->at(index);
-}
-
-// FIXME: move further up the plugin where there's more specific context
-// information available.
-static BreakpointData *createBreakpointByFileAndLine
- (const QString &fileName, int lineNumber, BreakHandler *handler)
-{
- BreakpointData *data = new BreakpointData(handler);
- if (lineNumber > 0) {
- data->fileName = fileName;
- data->lineNumber = QByteArray::number(lineNumber);
- data->pending = true;
- data->setMarkerFileName(fileName);
- data->setMarkerLineNumber(lineNumber);
- } else {
- data->funcName = fileName;
- data->lineNumber = 0;
- data->pending = true;
- // FIXME: Figure out in which disassembler view the Marker sits.
- // Might be better to let the user code create the BreakpointData
- // structure and insert it here.
- data->setMarkerFileName(QString());
- data->setMarkerLineNumber(0);
- }
- return data;
+ QTC_ASSERT(d->m_engine, return);
+ d->m_engine->activateSnapshot(index);
}
-void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber)
+void DebuggerManager::removeSnapshot(int index)
{
- STATE_DEBUG(fileName << lineNumber);
- QTC_ASSERT(d->m_breakHandler, return);
- if (state() != InferiorRunning
- && state() != InferiorStopped
- && state() != DebuggerNotReady) {
- showStatusMessage(tr("Changing breakpoint state requires either a "
- "fully running or fully stopped application."));
- return;
- }
-
- int index = d->m_breakHandler->findBreakpoint(fileName, lineNumber);
- if (index == -1)
- d->m_breakHandler->appendBreakpoint(
- createBreakpointByFileAndLine(fileName, lineNumber, d->m_breakHandler));
- else
- d->m_breakHandler->removeBreakpoint(index);
-
- attemptBreakpointSynchronization();
+ QTC_ASSERT(d->m_engine, return);
+ d->m_snapshotHandler->removeSnapshot(index);
}
void DebuggerManager::attemptBreakpointSynchronization()
QString *errorMessage,
QString *settingsIdHint)
{
+ if (executable.endsWith(_("qmlviewer"))) {
+ qDebug() << "HERE";
+ if (!qmlEngine) {
+ *errorMessage = msgEngineNotAvailable("Qml Engine");
+ return 0;
+ }
+ return qmlEngine;
+ }
+
if (executable.endsWith(_(".js"))) {
if (!scriptEngine) {
*errorMessage = msgEngineNotAvailable("Script Engine");
// We need the CDB debugger in order to be able to debug VS
// executables
- if (!DebuggerManager::instance()->checkDebugConfiguration(ProjectExplorer::ToolChain::MSVC, errorMessage, 0 , settingsIdHint))
+ if (!DebuggerManager::instance()->checkDebugConfiguration(
+ ProjectExplorer::ToolChain::MSVC, errorMessage, 0, settingsIdHint))
return 0;
return cdbEngine;
#endif
// Debugger type for mode
static IDebuggerEngine *debuggerEngineForMode(DebuggerStartMode startMode, QString *errorMessage)
{
+ if (startMode == AttachTcf)
+ return tcfEngine;
+
#ifdef Q_OS_WIN
// Preferably Windows debugger for attaching locally.
- if (startMode != StartRemote && cdbEngine)
+ if (startMode != AttachToRemote && cdbEngine)
return cdbEngine;
if (gdbEngine)
return gdbEngine;
#endif
}
-void DebuggerManager::startNewDebugger(const DebuggerStartParametersPtr &sp)
+void DebuggerManager::startNewDebugger(DebuggerRunControl *runControl)
{
if (d->m_state != DebuggerNotReady)
return;
- d->m_startParameters = sp;
+ d->m_runControl = runControl;
+ const DebuggerStartParameters *sp = &runControl->sp();
d->m_inferiorPid = sp->attachPID > 0 ? sp->attachPID : 0;
const QString toolChainName = ProjectExplorer::ToolChain::toolChainName(
ProjectExplorer::ToolChain::ToolChainType(sp->toolChainType));
d->m_plugin->activateDebugMode();
- showDebuggerOutput(LogStatus,
- tr("Starting debugger for tool chain '%1'...").arg(toolChainName));
- showDebuggerOutput(LogDebug, DebuggerSettings::instance()->dump());
+ showMessage(tr("Starting debugger for tool chain '%1'...").arg(toolChainName),
+ LogStatus);
+ showMessage(DebuggerSettings::instance()->dump(), LogDebug);
QString errorMessage;
QString settingsIdHint;
// Figure out engine: toolchain, executable, attach or default
const DebuggerStartMode startMode = sp->startMode;
- if (sp->executable.endsWith(_(".js")))
+ if (sp->executable.endsWith(_("qmlviewer")))
+ d->m_engine = qmlEngine;
+ else if (sp->executable.endsWith(_(".js")))
d->m_engine = scriptEngine;
else if (sp->executable.endsWith(_(".py")))
d->m_engine = pdbEngine;
d->m_engine = debuggerEngineForToolChain(sp->toolChainType);
if (d->m_engine == 0
- && startMode != StartRemote
+ && startMode != AttachToRemote
&& !sp->executable.isEmpty())
d->m_engine = debuggerEngineForExecutable(
sp->executable, &errorMessage, &settingsIdHint);
setBusyCursor(false);
setState(EngineStarting);
connect(d->m_engine, SIGNAL(startFailed()), this, SLOT(startFailed()));
- d->m_engine->startDebugger(sp);
+ d->m_engine->setRunControl(runControl);
+ d->m_engine->startDebugger();
const unsigned engineCapabilities = d->m_engine->debuggerCapabilities();
theDebuggerAction(OperateByInstruction)
d->m_disassemblerViewAgent.cleanup();
d->m_actions.reverseDirectionAction->setChecked(false);
d->m_actions.reverseDirectionAction->setEnabled(false);
+ hideDebuggerToolTip();
// FIXME: Move to plugin?
using namespace Core;
d->m_codeModelSnapshot = CPlusPlus::Snapshot();
}
-DebuggerStartParametersPtr DebuggerManager::startParameters() const
-{
- return d->m_startParameters;
-}
-
qint64 DebuggerManager::inferiorPid() const
{
return d->m_inferiorPid;
d->m_engine->loadSymbols(module);
}
-QList<Symbol> DebuggerManager::moduleSymbols(const QString &moduleName)
+void DebuggerManager::requestModuleSymbols(const QString &moduleName)
{
- QTC_ASSERT(d->m_engine, return QList<Symbol>());
- return d->m_engine->moduleSymbols(moduleName);
+ QTC_ASSERT(d->m_engine, return);
+ d->m_engine->requestModuleSymbols(moduleName);
+}
+
+void DebuggerManager::showModuleSymbols(const QString &moduleName,
+ const QList<Symbol> &symbols)
+{
+ QTC_ASSERT(d->m_engine, return);
+ QTreeWidget *w = new QTreeWidget;
+ w->setColumnCount(3);
+ w->setRootIsDecorated(false);
+ w->setAlternatingRowColors(true);
+ w->setSortingEnabled(true);
+ w->setHeaderLabels(QStringList() << tr("Symbol") << tr("Address") << tr("Code"));
+ w->setWindowTitle(tr("Symbols in \"%1\"").arg(moduleName));
+ foreach (const Symbol &s, symbols) {
+ QTreeWidgetItem *it = new QTreeWidgetItem;
+ it->setData(0, Qt::DisplayRole, s.name);
+ it->setData(1, Qt::DisplayRole, s.address);
+ it->setData(2, Qt::DisplayRole, s.state);
+ w->addTopLevelItem(it);
+ }
+ createNewDock(w);
}
void DebuggerManager::executeStep()
// Note that at startup, session switches may occur, which interfer
// with command-line debugging startup.
if (d->m_engine && state() != DebuggerNotReady
- && d->m_startParameters->startMode == StartInternal)
+ && runControl()->sp().startMode == StartInternal)
d->m_engine->shutdown();
}
QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor);
d->m_breakWindow->setCursor(cursor);
+ d->m_returnWindow->setCursor(cursor);
d->m_localsWindow->setCursor(cursor);
d->m_modulesWindow->setCursor(cursor);
d->m_outputWindow->setCursor(cursor);
reloadModules();
}
-
-//////////////////////////////////////////////////////////////////////
-//
-// Output specific stuff
-//
-//////////////////////////////////////////////////////////////////////
-
-void DebuggerManager::showDebuggerOutput(int channel, const QString &msg)
+void DebuggerManager::showMessage(const QString &msg, int channel)
{
- if (d->m_outputWindow) {
- emit emitShowOutput(channel, msg);
- if (channel == LogError)
- ensureLogVisible();
- } else {
+ if (runControl())
+ runControl()->showMessage(msg, channel);
+ else
qDebug() << "OUTPUT: " << channel << msg;
-
- }
-}
-
-void DebuggerManager::showDebuggerInput(int channel, const QString &msg)
-{
- if (d->m_outputWindow)
- emit emitShowInput(channel, msg);
- else
- qDebug() << "INPUT: " << channel << msg;
}
{
if (theDebuggerAction(UseCustomDebuggingHelperLocation)->value().toBool())
return theDebuggerAction(CustomDebuggingHelperLocation)->value().toString();
- return d->m_startParameters->dumperLibrary;
+ return runControl()->sp().dumperLibrary;
}
QStringList DebuggerManager::qtDumperLibraryLocations() const
tr("%1 (explicitly set in the Debugger Options)").arg(customLocation);
return QStringList(location);
}
- return d->m_startParameters->dumperLibraryLocations;
+ return runControl()->sp().dumperLibraryLocations;
}
void DebuggerManager::showQtDumperLibraryWarning(const QString &details)
dialog.setDetailedText(details);
dialog.exec();
if (dialog.clickedButton() == qtPref) {
- Core::ICore::instance()->showOptionsDialog(_(Qt4ProjectManager::Constants::QT_SETTINGS_CATEGORY),
- _(Qt4ProjectManager::Constants::QTVERSION_SETTINGS_PAGE_ID));
+ Core::ICore::instance()->showOptionsDialog(
+ _(Qt4ProjectManager::Constants::QT_SETTINGS_CATEGORY),
+ _(Qt4ProjectManager::Constants::QTVERSION_SETTINGS_PAGE_ID));
} else if (dialog.clickedButton() == helperOff) {
- theDebuggerAction(UseDebuggingHelpers)->setValue(qVariantFromValue(false), false);
+ theDebuggerAction(UseDebuggingHelpers)
+ ->setValue(qVariantFromValue(false), false);
}
}
if (!forced && !isAllowedTransition(d->m_state, state))
qDebug() << "UNEXPECTED STATE TRANSITION: " << msg;
- showDebuggerOutput(LogDebug, msg);
+ showMessage(msg, LogDebug);
//resetLocation();
if (state == d->m_state)
void DebuggerManager::fontSettingsChanged(const TextEditor::FontSettings &settings)
{
int size = settings.fontZoom() * settings.fontSize() / 100;
+ changeFontSize(d->m_returnWindow, size);
changeFontSize(d->m_localsWindow, size);
changeFontSize(d->m_watchersWindow, size);
changeFontSize(d->m_breakWindow, size);
{
d->m_watchersWindow->setVisible(
d->m_watchHandler->model(WatchersWatch)->rowCount(QModelIndex()) > 0);
+ d->m_returnWindow->setVisible(
+ d->m_watchHandler->model(ReturnWatch)->rowCount(QModelIndex()) > 0);
}
void DebuggerManager::openTextEditor(const QString &titlePattern,
d->m_plugin->openTextEditor(titlePattern, contents);
}
+DebuggerRunControl *DebuggerManager::runControl() const
+{
+ return const_cast<DebuggerRunControl *>(d->m_runControl);
+}
+
+DebuggerOutputWindow *DebuggerManager::debuggerOutputWindow() const
+{
+ return d->m_outputWindow;
+}
+
+
//////////////////////////////////////////////////////////////////////
//
// AbstractDebuggerEngine
//
//////////////////////////////////////////////////////////////////////
+/*
void IDebuggerEngine::showStatusMessage(const QString &msg, int timeout)
{
m_manager->showStatusMessage(msg, timeout);
}
+*/
DebuggerState IDebuggerEngine::state() const
{
m_manager->setState(state, forced);
}
+
//////////////////////////////////////////////////////////////////////
//
// Testing
//
//////////////////////////////////////////////////////////////////////
+/*
void DebuggerManager::runTest(const QString &fileName)
{
d->m_startParameters->executable = fileName;
d->m_startParameters->processArgs = QStringList() << "--run-debuggee";
- d->m_startParameters->workingDir.clear();
+ d->m_startParameters->workingDirectory.clear();
//startNewDebugger(StartInternal);
}
+*/
} // namespace Debugger
#include "debugger_global.h"
#include "debuggerconstants.h"
+#include "debuggerrunner.h"
#include <QtCore/QObject>
#include <QtCore/QSharedPointer>
class CdbDumperInitThread;
class CdbExceptionLoggerEventCallback;
class GdbEngine;
+class TcfEngine;
+class QmlEngine;
class CdbDebugEngine;
class CdbDebugEnginePrivate;
class TrkGdbAdapter;
class BreakpointMarker;
} // namespace Internal
-class DEBUGGER_EXPORT DebuggerStartParameters
-{
-public:
- DebuggerStartParameters();
- void clear();
-
- QString executable;
- QString coreFile;
- QStringList processArgs;
- QStringList environment;
- QString workingDir;
- QString buildDir;
- qint64 attachPID;
- bool useTerminal;
- QString crashParameter; // for AttachCrashedExternal
- // for remote debugging
- QString remoteChannel;
- QString remoteArchitecture;
- QString symbolFileName;
- QString serverStartScript;
- QString sysRoot;
- QString debuggerCommand;
- int toolChainType;
- QString remoteDumperLib;
- QString qtInstallPath;
-
- QString dumperLibrary;
- QStringList dumperLibraryLocations;
- DebuggerStartMode startMode;
-};
-
-typedef QSharedPointer<DebuggerStartParameters> DebuggerStartParametersPtr;
-
-DEBUGGER_EXPORT QDebug operator<<(QDebug str, const DebuggerStartParameters &);
-
// Flags for initialization
enum DebuggerEngineTypeFlags
{
ScriptEngineType = 0x02,
CdbEngineType = 0x04,
PdbEngineType = 0x08,
+ TcfEngineType = 0x10,
+ QmlEngineType = 0x20,
AllEngineTypes = GdbEngineType
| ScriptEngineType
| CdbEngineType
| PdbEngineType
+ | TcfEngineType
+ | QmlEngineType
};
QDebug operator<<(QDebug d, DebuggerState state);
friend class Internal::GdbEngine;
friend class Internal::ScriptEngine;
friend class Internal::PdbEngine;
+ friend class Internal::TcfEngine;
+ friend class Internal::QmlEngine;
friend class Internal::CdbDebugEngine;
friend class Internal::CdbDebugEnginePrivate;
friend class Internal::TrkGdbAdapter;
QLabel *statusLabel() const;
Internal::IDebuggerEngine *currentEngine() const;
- DebuggerStartParametersPtr startParameters() const;
+ DebuggerRunControl *runControl() const;
qint64 inferiorPid() const;
QMessageBox *showMessageBox(int icon, const QString &title, const QString &text,
static DebuggerManager *instance();
+ void startNewDebugger(DebuggerRunControl *runControl);
public slots:
- void startNewDebugger(const DebuggerStartParametersPtr &sp);
void exitDebugger();
void abortDebugger();
void executeReturn();
void detachDebugger();
void makeSnapshot();
+ void frameUp();
+ void frameDown();
void addToWatchWindow();
void updateWatchData(const Debugger::Internal::WatchData &data);
static const char *stateName(int s);
public slots: // FIXME
- void showDebuggerOutput(const QString &msg)
- { showDebuggerOutput(LogDebug, msg); }
void ensureLogVisible();
void updateWatchersWindow();
void updateWatchersHeader(int section, int oldSize, int newSize);
void activateBreakpoint(int index);
//private slots: // FIXME
- void showDebuggerOutput(int channel, const QString &msg);
- void showDebuggerInput(int channel, const QString &msg);
- void showApplicationOutput(const QString &data, bool onStdErr);
-
void reloadSourceFiles();
void sourceFilesDockToggled(bool on);
void operateByInstructionTriggered();
void startFailed();
-private:
+public:
Internal::ModulesHandler *modulesHandler() const;
Internal::BreakHandler *breakHandler() const;
Internal::RegisterHandler *registerHandler() const;
Internal::ThreadsHandler *threadsHandler() const;
Internal::WatchHandler *watchHandler() const;
Internal::SnapshotHandler *snapshotHandler() const;
+ Internal::DebuggerOutputWindow *debuggerOutputWindow() const;
+
+private:
Internal::SourceFilesWindow *sourceFileWindow() const;
QWidget *threadsWindow() const;
public:
// stuff in this block should be made private by moving it to
// one of the interfaces
- QList<Internal::Symbol> moduleSymbols(const QString &moduleName);
+ void requestModuleSymbols(const QString &moduleName);
+ void showModuleSymbols(const QString &moduleName,
+ const QList<Internal::Symbol> &symbols);
signals:
void debuggingFinished();
void statusMessageRequested(const QString &msg, int timeout); // -1 for 'forever'
void applicationOutputAvailable(const QString &output, bool onStdErr);
void messageAvailable(const QString &output, bool isError);
- void emitShowOutput(int channel, const QString &output);
- void emitShowInput(int channel, const QString &input);
private:
void init();
- void runTest(const QString &fileName);
+ // void runTest(const QString &fileName);
+ void showMessage(const QString &msg, int channel);
Q_SLOT void createNewDock(QWidget *widget);
void aboutToShutdown();
- void toggleBreakpoint(const QString &fileName, int lineNumber);
- Internal::BreakpointData *findBreakpoint(const QString &fileName, int lineNumber);
+ //void toggleBreakpoint(const QString &fileName, int lineNumber);
void setToolTipExpression(const QPoint &mousePos,
TextEditor::ITextEditor *editor, int cursorPos);
void openTextEditor(const QString &titlePattern,
#include "debuggermanager.h"
#include <QtCore/QDebug>
+#include <QtCore/QFile>
#include <QtGui/QAction>
#include <QtGui/QHBoxLayout>
#include <QtGui/QSyntaxHighlighter>
#include <QtGui/QTextBlock>
#include <QtGui/QPlainTextEdit>
+#include <QtGui/QFileDialog>
+#include <QtGui/QMessageBox>
#include <aggregation/aggregate.h>
#include <coreplugin/findplaceholder.h>
m_saveContentsAction = new QAction(this);
m_saveContentsAction->setText(tr("Save Contents"));
m_saveContentsAction->setEnabled(true);
+ connect(m_saveContentsAction, SIGNAL(triggered()), this, SLOT(saveContents()));
}
void contextMenuEvent(QContextMenuEvent *ev)
{
QMenu *menu = createStandardContextMenu();
menu->addAction(m_clearContentsAction);
- //menu->addAction(m_saveContentsAction);
+ menu->addAction(m_saveContentsAction); // X11 clipboard is unreliable for long texts
addContextActions(menu);
theDebuggerAction(ExecuteCommand)->setData(textCursor().block().text());
menu->addAction(theDebuggerAction(ExecuteCommand));
virtual void addContextActions(QMenu *) {}
-public:
+private slots:
+ void saveContents();
+
+private:
QAction *m_clearContentsAction;
QAction *m_saveContentsAction;
};
+void DebuggerPane::saveContents()
+{
+ while (true) {
+ const QString fileName = QFileDialog::getSaveFileName(this, tr("Log File"));
+ if (fileName.isEmpty())
+ break;
+ QFile file(fileName);
+ if (file.open(QIODevice::WriteOnly|QIODevice::Text|QIODevice::Truncate)) {
+ file.write(toPlainText().toUtf8());
+ file.close();
+ break;
+ } else {
+ QMessageBox::warning(this, tr("Write Failure"),
+ tr("Unable to write log contents to '%1': %2").
+ arg(fileName, file.errorString()));
+ }
+ }
+}
+
/////////////////////////////////////////////////////////////////////
//
#include <coreplugin/findplaceholder.h>
#include <coreplugin/icore.h>
#include <coreplugin/icorelistener.h>
+#include <coreplugin/manhattanstyle.h>
#include <coreplugin/messagemanager.h>
#include <coreplugin/minisplitter.h>
#include <coreplugin/modemanager.h>
#include <extensionsystem/pluginmanager.h>
-#include <coreplugin/manhattanstyle.h>
+#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/session.h>
-#include <projectexplorer/project.h>
+#include <projectexplorer/toolchain.h>
#include <texteditor/basetexteditor.h>
#include <texteditor/basetextmark.h>
const char * const STARTEXTERNAL = "Debugger.StartExternal";
const char * const ATTACHEXTERNAL = "Debugger.AttachExternal";
const char * const ATTACHCORE = "Debugger.AttachCore";
+const char * const ATTACHTCF = "Debugger.AttachTcf";
const char * const ATTACHREMOTE = "Debugger.AttachRemote";
const char * const DETACH = "Debugger.Detach";
const char * const ADD_TO_WATCH1 = "Debugger.AddToWatch1";
const char * const ADD_TO_WATCH2 = "Debugger.AddToWatch2";
const char * const OPERATE_BY_INSTRUCTION = "Debugger.OperateByInstruction";
+const char * const FRAME_UP = "Debugger.FrameUp";
+const char * const FRAME_DOWN = "Debugger.FrameDown";
#ifdef Q_WS_MAC
const char * const INTERRUPT_KEY = "Shift+F5";
}
return true;
}
- // engine disabling
+ // Engine disabling.
if (option == _("-disable-cdb")) {
*enabledEngines &= ~Debugger::CdbEngineType;
return true;
*enabledEngines &= ~Debugger::GdbEngineType;
return true;
}
+ if (option == _("-disable-qmldb")) {
+ *enabledEngines &= ~Debugger::QmlEngineType;
+ return true;
+ }
if (option == _("-disable-sdb")) {
*enabledEngines &= ~Debugger::ScriptEngineType;
return true;
}
+ if (option == _("-disable-tcf")) {
+ *enabledEngines &= ~TcfEngineType;
+ return true;
+ }
*errorMessage = DebuggerPlugin::tr("Invalid debugger option: %1").arg(option);
return false;
}
static bool parseArguments(const QStringList &args,
- DebuggerPlugin::AttachRemoteParameters *attachRemoteParameters,
- unsigned *enabledEngines, QString *errorMessage)
+ DebuggerPlugin::AttachRemoteParameters *attachRemoteParameters,
+ unsigned *enabledEngines, QString *errorMessage)
{
const QStringList::const_iterator cend = args.constEnd();
for (QStringList::const_iterator it = args.constBegin(); it != cend; ++it)
m_attachCoreAction->setText(tr("Attach to Core..."));
connect(m_attachCoreAction, SIGNAL(triggered()), this, SLOT(attachCore()));
+ m_attachTcfAction = new QAction(this);
+ m_attachTcfAction->setText(tr("Attach to Running Tcf Agent..."));
+ m_attachTcfAction->setToolTip(tr("This attaches to a running "
+ "'Target Communication Framework' agent."));
+ connect(m_attachTcfAction, SIGNAL(triggered()),
+ this, SLOT(attachRemoteTcf()));
+
m_startRemoteAction = new QAction(this);
m_startRemoteAction->setText(tr("Start and Attach to Remote Application..."));
connect(m_startRemoteAction, SIGNAL(triggered()),
cmd = am->registerAction(m_attachCoreAction,
Constants::ATTACHCORE, globalcontext);
+
cmd->setAttribute(Command::CA_Hide);
mstart->addAction(cmd, CC::G_DEFAULT_ONE);
+ cmd = am->registerAction(m_attachTcfAction,
+ Constants::ATTACHTCF, globalcontext);
+ mstart->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
+
cmd = am->registerAction(m_startRemoteAction,
Constants::ATTACHREMOTE, globalcontext);
cmd->setAttribute(Command::CA_Hide);
cmd->setAttribute(Command::CA_Hide);
m_uiSwitcher->addMenuAction(cmd, Constants::LANG_CPP);
+ cmd = am->registerAction(actions.frameDownAction,
+ Constants::FRAME_DOWN, cppDebuggercontext);
+ cmd = am->registerAction(actions.frameUpAction,
+ Constants::FRAME_UP, cppDebuggercontext);
+
cmd = am->registerAction(theDebuggerAction(OperateByInstruction),
Constants::OPERATE_BY_INSTRUCTION, cppDebuggercontext);
// time gdb -i mi -ex 'debuggerplugin.cpp:800' -ex r -ex q bin/qtcreator.bin
const QByteArray env = qgetenv("QTC_DEBUGGER_TEST");
//qDebug() << "EXTENSIONS INITIALIZED:" << env;
- if (!env.isEmpty())
- m_manager->runTest(QString::fromLocal8Bit(env));
+ // if (!env.isEmpty())
+ // m_manager->runTest(QString::fromLocal8Bit(env));
if (m_attachRemoteParameters.attachPid || !m_attachRemoteParameters.attachCore.isEmpty())
QTimer::singleShot(0, this, SLOT(attachCmdLine()));
if (!isDebuggable(editor))
return;
- QString fileName, position;
+ BreakHandler *handler = m_manager->breakHandler();
+ QTC_ASSERT(handler, return);
+
+ BreakpointData *data = 0;
+ QString position;
if (editor->property("DisassemblerView").toBool()) {
QString fileName = editor->file()->fileName();
QString line = editor->contents()
.section('\n', lineNumber - 1, lineNumber - 1);
- fileName = line.left(line.indexOf(QLatin1Char(' ')));
- lineNumber = -1;
position = _("*") + fileName;
+ BreakpointData needle;
+ needle.bpAddress = line.left(line.indexOf(QLatin1Char(' '))).toLatin1();
+ needle.bpLineNumber = "-1";
+ data = handler->findSimilarBreakpoint(needle);
} else {
- fileName = editor->file()->fileName();
+ QString fileName = editor->file()->fileName();
position = fileName + QString(":%1").arg(lineNumber);
+ BreakpointData needle;
+ needle.bpFileName = fileName;
+ needle.bpLineNumber = QByteArray::number(lineNumber);
+ data = handler->findSimilarBreakpoint(needle);
}
- BreakpointData *data = m_manager->findBreakpoint(fileName, lineNumber);
if (data) {
// existing breakpoint
}
}
+void DebuggerPlugin::toggleBreakpoint()
+{
+ ITextEditor *textEditor = currentTextEditor();
+ QTC_ASSERT(textEditor, return);
+ int lineNumber = textEditor->currentLine();
+ if (lineNumber >= 0)
+ toggleBreakpoint(textEditor->file()->fileName(), lineNumber);
+}
+
+void DebuggerPlugin::toggleBreakpoint(const QString &fileName, int lineNumber)
+{
+ BreakHandler *handler = m_manager->breakHandler();
+ QTC_ASSERT(handler, return);
+ BreakpointData needle;
+ needle.bpFileName = fileName;
+ needle.bpLineNumber.setNum(lineNumber);
+ BreakpointData *data = handler->findSimilarBreakpoint(needle);
+ if (data) {
+ handler->removeBreakpoint(data);
+ } else {
+ data = new BreakpointData;
+ data->fileName = fileName;
+ data->lineNumber = QByteArray::number(lineNumber);
+ data->pending = true;
+ data->setMarkerFileName(fileName);
+ data->setMarkerLineNumber(lineNumber);
+ handler->appendBreakpoint(data);
+ }
+ m_manager->attemptBreakpointSynchronization();
+}
+
void DebuggerPlugin::breakpointSetRemoveMarginActionTriggered()
{
QAction *act = qobject_cast<QAction *>(sender());
QTC_ASSERT(act, return);
+ BreakHandler *handler = m_manager->breakHandler();
+ QTC_ASSERT(handler, return);
QString str = act->data().toString();
int pos = str.lastIndexOf(':');
- m_manager->toggleBreakpoint(str.left(pos), str.mid(pos + 1).toInt());
+ toggleBreakpoint(str.left(pos), str.mid(pos + 1).toInt());
}
void DebuggerPlugin::breakpointEnableDisableMarginActionTriggered()
QString str = act->data().toString();
int pos = str.lastIndexOf(':');
- QString fileName = str.left(pos);
- int lineNumber = str.mid(pos + 1).toInt();
-
- BreakpointData *data = handler->at(handler->findBreakpoint(fileName, lineNumber));
+ BreakpointData needle;
+ needle.bpFileName = str.left(pos);
+ needle.bpLineNumber = str.mid(pos + 1).toLatin1();
+ BreakpointData *data = handler->findSimilarBreakpoint(needle);
+ QTC_ASSERT(data, return);
handler->toggleBreakpointEnabled(data);
-
m_manager->attemptBreakpointSynchronization();
}
{
if (!isDebuggable(editor))
return;
- m_manager->toggleBreakpoint(editor->file()->fileName(), lineNumber);
+ toggleBreakpoint(editor->file()->fileName(), lineNumber);
}
void DebuggerPlugin::showToolTip(ITextEditor *editor, const QPoint &point, int pos)
//const bool running = state == InferiorRunning;
const bool detachable = state == InferiorStopped
- && m_manager->startParameters()->startMode != AttachCore;
+ && m_manager->runControl()->sp().startMode != AttachCore;
m_startExternalAction->setEnabled(!started && !starting);
m_attachExternalAction->setEnabled(!started && !starting);
m_attachCoreAction->setVisible(debuggerIsCPP);
m_startRemoteAction->setVisible(debuggerIsCPP);
m_detachAction->setVisible(debuggerIsCPP);
-
}
void DebuggerPlugin::writeSettings() const
if (isCurrentProjectCppBased())
m_uiSwitcher->setActiveLanguage(LANG_CPP);
-
}
}
-
-
void DebuggerPlugin::showSettingsDialog()
{
Core::ICore::instance()->showOptionsDialog(
void DebuggerPlugin::startExternalApplication()
{
- const DebuggerStartParametersPtr sp(new DebuggerStartParameters);
+ DebuggerStartParameters sp;
StartExternalDialog dlg(m_uiSwitcher->mainWindow());
dlg.setExecutableFile(
configValue(_("LastExternalExecutableFile")).toString());
dlg.setExecutableArguments(
configValue(_("LastExternalExecutableArguments")).toString());
+ dlg.setWorkingDirectory(
+ configValue(_("LastExternalWorkingDirectory")).toString());
if (dlg.exec() != QDialog::Accepted)
return;
dlg.executableFile());
setConfigValue(_("LastExternalExecutableArguments"),
dlg.executableArguments());
- sp->executable = dlg.executableFile();
- sp->startMode = StartExternal;
+ setConfigValue(_("LastExternalWorkingDirectory"),
+ dlg.workingDirectory());
+ sp.executable = dlg.executableFile();
+ sp.startMode = StartExternal;
+ sp.workingDirectory = dlg.workingDirectory();
if (!dlg.executableArguments().isEmpty())
- sp->processArgs = dlg.executableArguments().split(QLatin1Char(' '));
+ sp.processArgs = dlg.executableArguments().split(QLatin1Char(' '));
if (dlg.breakAtMain())
m_manager->breakByFunctionMain();
tr("Cannot attach to PID 0"));
return;
}
- const DebuggerStartParametersPtr sp(new DebuggerStartParameters);
- sp->attachPID = pid;
- sp->executable = binary;
- sp->crashParameter = crashParameter;
- sp->startMode = crashParameter.isEmpty() ? AttachExternal : AttachCrashedExternal;
+ DebuggerStartParameters sp;
+ sp.attachPID = pid;
+ sp.executable = binary;
+ sp.crashParameter = crashParameter;
+ sp.startMode = crashParameter.isEmpty() ? AttachExternal : AttachCrashedExternal;
if (RunControl *runControl = m_debuggerRunControlFactory->create(sp))
ProjectExplorerPlugin::instance()->startRunControl(runControl, PE::DEBUGMODE);
}
void DebuggerPlugin::attachCore(const QString &core, const QString &exe)
{
- const DebuggerStartParametersPtr sp(new DebuggerStartParameters);
- sp->executable = exe;
- sp->coreFile = core;
- sp->startMode = AttachCore;
+ DebuggerStartParameters sp;
+ sp.executable = exe;
+ sp.coreFile = core;
+ sp.displayName = tr("Core file: \"%1\"").arg(core);
+ sp.startMode = AttachCore;
if (RunControl *runControl = m_debuggerRunControlFactory->create(sp))
ProjectExplorerPlugin::instance()->
startRunControl(runControl, PE::DEBUGMODE);
void DebuggerPlugin::startRemoteApplication()
{
- const DebuggerStartParametersPtr sp(new DebuggerStartParameters);
+ DebuggerStartParameters sp;
StartRemoteDialog dlg(m_uiSwitcher->mainWindow());
QStringList arches;
arches.append(_("i386:x86-64:intel"));
setConfigValue(_("LastServerStartScript"), dlg.serverStartScript());
setConfigValue(_("LastUseServerStartScript"), dlg.useServerStartScript());
setConfigValue(_("LastSysroot"), dlg.sysRoot());
- sp->remoteChannel = dlg.remoteChannel();
- sp->remoteArchitecture = dlg.remoteArchitecture();
- sp->executable = dlg.localExecutable();
- sp->debuggerCommand = dlg.debugger(); // Override toolchain-detection.
- if (!sp->debuggerCommand.isEmpty())
- sp->toolChainType = ProjectExplorer::ToolChain::INVALID;
- sp->startMode = StartRemote;
+ sp.remoteChannel = dlg.remoteChannel();
+ sp.remoteArchitecture = dlg.remoteArchitecture();
+ sp.executable = dlg.localExecutable();
+ sp.displayName = dlg.localExecutable();
+ sp.debuggerCommand = dlg.debugger(); // Override toolchain-detection.
+ if (!sp.debuggerCommand.isEmpty())
+ sp.toolChainType = ProjectExplorer::ToolChain::INVALID;
+ sp.startMode = AttachToRemote;
if (dlg.useServerStartScript())
- sp->serverStartScript = dlg.serverStartScript();
- sp->sysRoot = dlg.sysRoot();
+ sp.serverStartScript = dlg.serverStartScript();
+ sp.sysRoot = dlg.sysRoot();
if (RunControl *runControl = m_debuggerRunControlFactory->create(sp))
ProjectExplorerPlugin::instance()
m_manager->debuggerManagerActions().reverseDirectionAction->setEnabled(value.toBool());
}
-void DebuggerPlugin::toggleBreakpoint()
+void DebuggerPlugin::attachRemoteTcf()
{
- ITextEditor *textEditor = currentTextEditor();
- QTC_ASSERT(textEditor, return);
- QString fileName = textEditor->file()->fileName();
- int lineNumber = textEditor->currentLine();
- if (lineNumber >= 0)
- m_manager->toggleBreakpoint(fileName, lineNumber);
+ DebuggerStartParameters sp;
+ AttachTcfDialog dlg(m_uiSwitcher->mainWindow());
+ QStringList arches;
+ arches.append(_("i386:x86-64:intel"));
+ dlg.setRemoteArchitectures(arches);
+ dlg.setRemoteChannel(
+ configValue(_("LastTcfRemoteChannel")).toString());
+ dlg.setRemoteArchitecture(
+ configValue(_("LastTcfRemoteArchitecture")).toString());
+ dlg.setServerStartScript(
+ configValue(_("LastTcfServerStartScript")).toString());
+ dlg.setUseServerStartScript(
+ configValue(_("LastTcfUseServerStartScript")).toBool());
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+ setConfigValue(_("LastTcfRemoteChannel"), dlg.remoteChannel());
+ setConfigValue(_("LastTcfRemoteArchitecture"), dlg.remoteArchitecture());
+ setConfigValue(_("LastTcfServerStartScript"), dlg.serverStartScript());
+ setConfigValue(_("LastTcfUseServerStartScript"), dlg.useServerStartScript());
+ sp.remoteChannel = dlg.remoteChannel();
+ sp.remoteArchitecture = dlg.remoteArchitecture();
+ sp.serverStartScript = dlg.serverStartScript();
+ sp.startMode = AttachTcf;
+ if (dlg.useServerStartScript())
+ sp.serverStartScript = dlg.serverStartScript();
+
+ if (RunControl *runControl = m_debuggerRunControlFactory->create(sp))
+ ProjectExplorerPlugin::instance()
+ ->startRunControl(runControl, PE::DEBUGMODE);
}
#include "debuggerplugin.moc"
class DebuggerManager;
class DebuggerUISwitcher;
+class DebuggerRunControlFactory;
namespace Internal {
class BreakpointData;
-class DebuggerRunControlFactory;
class DebugMode;
class DebuggerPlugin : public ExtensionSystem::IPlugin
~DebuggerPlugin();
private:
- virtual bool initialize(const QStringList &arguments, QString *error_message);
- virtual void aboutToShutdown();
- virtual void extensionsInitialized();
- virtual void remoteCommand(const QStringList &options, const QStringList &arguments);
+ bool initialize(const QStringList &arguments, QString *error_message);
+ void aboutToShutdown();
+ void extensionsInitialized();
+ void remoteCommand(const QStringList &options, const QStringList &arguments);
QVariant configValue(const QString &name) const;
TextEditor::ITextEditor *currentTextEditor();
private slots:
void activatePreviousMode();
void activateDebugMode();
- void editorOpened(Core::IEditor *);
- void editorAboutToClose(Core::IEditor *);
+ void editorOpened(Core::IEditor *editor);
+ void editorAboutToClose(Core::IEditor *editor);
void handleStateChanged(int state);
void requestMark(TextEditor::ITextEditor *editor, int lineNumber);
void showToolTip(TextEditor::ITextEditor *editor, const QPoint &pnt, int pos);
int lineNumber, QMenu *menu);
void resetLocation();
- void gotoLocation(const QString &file, int line, bool setMarker);
+ void gotoLocation(const QString &fileName, int lineNumber, bool setMarker);
void openTextEditor(const QString &titlePattern, const QString &contents);
void toggleBreakpoint();
+ void toggleBreakpoint(const QString &fileName, int lineNumber);
void breakpointSetRemoveMarginActionTriggered();
void breakpointEnableDisableMarginActionTriggered();
void onModeChanged(Core::IMode *mode);
void attachExternalApplication();
void attachCore();
void attachCmdLine();
+ void attachRemoteTcf();
void enableReverseDebuggingTriggered(const QVariant &value);
void languageChanged(const QString &debuggerLanguage);
QAction *m_startRemoteAction;
QAction *m_attachExternalAction;
QAction *m_attachCoreAction;
+ QAction *m_attachTcfAction;
QAction *m_detachAction;
QComboBox *m_langBox;
QToolButton *m_reverseToolButton;
**************************************************************************/
#include "debuggerrunner.h"
+#include "debuggermanager.h"
+#include "debuggeroutputwindow.h"
#include <projectexplorer/debugginghelper.h>
#include <projectexplorer/environment.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <projectexplorer/buildconfiguration.h>
+#include <projectexplorer/applicationrunconfiguration.h> // For LocalApplication*
#include <utils/qtcassert.h>
#include <coreplugin/icore.h>
#include <QtGui/QTextDocument>
-namespace Debugger {
-namespace Internal {
+using namespace ProjectExplorer;
+using namespace Debugger::Internal;
+
-using ProjectExplorer::RunConfiguration;
-using ProjectExplorer::RunControl;
-using ProjectExplorer::LocalApplicationRunConfiguration;
+namespace Debugger {
////////////////////////////////////////////////////////////////////////
//
bool DebuggerRunControlFactory::canRun(RunConfiguration *runConfiguration, const QString &mode) const
{
+// return mode == ProjectExplorer::Constants::DEBUGMODE;
return mode == ProjectExplorer::Constants::DEBUGMODE
&& qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
}
return tr("Debug");
}
-RunControl *DebuggerRunControlFactory::create(const DebuggerStartParametersPtr &sp)
+static DebuggerStartParameters localStartParameters(RunConfiguration *runConfiguration)
{
- return new DebuggerRunControl(m_manager, sp);
+ DebuggerStartParameters sp;
+ QTC_ASSERT(runConfiguration, return sp);
+ LocalApplicationRunConfiguration *rc =
+ qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
+ QTC_ASSERT(rc, return sp);
+
+ sp.startMode = StartInternal;
+ sp.executable = rc->executable();
+ sp.environment = rc->environment().toStringList();
+ sp.workingDirectory = rc->workingDirectory();
+ sp.processArgs = rc->commandLineArguments();
+ sp.toolChainType = rc->toolChainType();
+ sp.useTerminal = rc->runMode() == LocalApplicationRunConfiguration::Console;
+ sp.dumperLibrary = rc->dumperLibrary();
+ sp.dumperLibraryLocations = rc->dumperLibraryLocations();
+ sp.displayName = rc->displayName();
+
+ // Find qtInstallPath.
+ QString qmakePath = DebuggingHelperLibrary::findSystemQt(rc->environment());
+ if (!qmakePath.isEmpty()) {
+ QProcess proc;
+ QStringList args;
+ args.append(QLatin1String("-query"));
+ args.append(QLatin1String("QT_INSTALL_HEADERS"));
+ proc.start(qmakePath, args);
+ proc.waitForFinished();
+ QByteArray ba = proc.readAllStandardOutput().trimmed();
+ QFileInfo fi(QString::fromLocal8Bit(ba) + "/..");
+ sp.qtInstallPath = fi.absoluteFilePath();
+ }
+ return sp;
}
RunControl *DebuggerRunControlFactory::create(RunConfiguration *runConfiguration,
const QString &mode)
{
QTC_ASSERT(mode == ProjectExplorer::Constants::DEBUGMODE, return 0);
- LocalApplicationRunConfiguration *rc = qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
- QTC_ASSERT(rc, return 0);
- return new DebuggerRunControl(m_manager, rc);
+ DebuggerStartParameters sp = localStartParameters(runConfiguration);
+ return new DebuggerRunControl(m_manager, sp);
+}
+
+RunControl *DebuggerRunControlFactory::create(const DebuggerStartParameters &sp)
+{
+ return new DebuggerRunControl(m_manager, sp);
}
QWidget *DebuggerRunControlFactory::createConfigurationWidget(RunConfiguration *runConfiguration)
//
////////////////////////////////////////////////////////////////////////
-
DebuggerRunControl::DebuggerRunControl(DebuggerManager *manager,
- LocalApplicationRunConfiguration *runConfiguration)
- : RunControl(runConfiguration),
- m_startParameters(new DebuggerStartParameters()),
- m_manager(manager),
- m_running(false)
-{
- init();
- if (!runConfiguration)
- return;
-
- m_startParameters->startMode = StartInternal;
- m_startParameters->executable = runConfiguration->executable();
- m_startParameters->environment = runConfiguration->environment().toStringList();
- m_startParameters->workingDir = runConfiguration->workingDirectory();
- m_startParameters->processArgs = runConfiguration->commandLineArguments();
-
- switch (m_startParameters->toolChainType) {
- case ProjectExplorer::ToolChain::UNKNOWN:
- case ProjectExplorer::ToolChain::INVALID:
- m_startParameters->toolChainType = runConfiguration->toolChainType();
- break;
- default:
- break;
- }
- if (runConfiguration->target()->project()) {
- m_startParameters->buildDir =
- runConfiguration->target()->activeBuildConfiguration()->buildDirectory();
- }
- m_startParameters->useTerminal =
- runConfiguration->runMode() == LocalApplicationRunConfiguration::Console;
- m_startParameters->dumperLibrary =
- runConfiguration->dumperLibrary();
- m_startParameters->dumperLibraryLocations =
- runConfiguration->dumperLibraryLocations();
-
- QString qmakePath = ProjectExplorer::DebuggingHelperLibrary::findSystemQt(
- runConfiguration->environment());
- if (!qmakePath.isEmpty()) {
- QProcess proc;
- QStringList args;
- args.append(QLatin1String("-query"));
- args.append(QLatin1String("QT_INSTALL_HEADERS"));
- proc.start(qmakePath, args);
- proc.waitForFinished();
- QByteArray ba = proc.readAllStandardOutput().trimmed();
- QFileInfo fi(QString::fromLocal8Bit(ba) + "/..");
- m_startParameters->qtInstallPath = fi.absoluteFilePath();
- }
-
-}
-
-DebuggerRunControl::DebuggerRunControl(DebuggerManager *manager, const DebuggerStartParametersPtr &startParameters)
- : RunControl(0),
+ const DebuggerStartParameters &startParameters)
+ : RunControl(0, ProjectExplorer::Constants::DEBUGMODE),
m_startParameters(startParameters),
m_manager(manager),
m_running(false)
{
- init();
-
- if (m_startParameters->environment.empty())
- m_startParameters->environment = ProjectExplorer::Environment().toStringList();
- m_startParameters->useTerminal = false;
-}
-
-void DebuggerRunControl::setCustomEnvironment(ProjectExplorer::Environment env)
-{
- m_startParameters->environment = env.toStringList();
-}
-
-void DebuggerRunControl::init()
-{
connect(m_manager, SIGNAL(debuggingFinished()),
this, SLOT(debuggingFinished()),
Qt::QueuedConnection);
- connect(m_manager, SIGNAL(applicationOutputAvailable(QString, bool)),
- this, SLOT(slotAddToOutputWindowInline(QString, bool)),
- Qt::QueuedConnection);
connect(m_manager, SIGNAL(messageAvailable(QString, bool)),
this, SLOT(slotMessageAvailable(QString, bool)));
connect(m_manager, SIGNAL(inferiorPidChanged(qint64)),
Qt::QueuedConnection);
connect(this, SIGNAL(stopRequested()),
m_manager, SLOT(exitDebugger()));
+
+ if (m_startParameters.environment.empty())
+ m_startParameters.environment = ProjectExplorer::Environment().toStringList();
+ m_startParameters.useTerminal = false;
+
+}
+
+QString DebuggerRunControl::displayName() const
+{
+ return m_startParameters.displayName;
+}
+
+void DebuggerRunControl::setCustomEnvironment(ProjectExplorer::Environment env)
+{
+ m_startParameters.environment = env.toStringList();
+}
+
+void DebuggerRunControl::init()
+{
}
void DebuggerRunControl::start()
QString errorMessage;
QString settingsCategory;
QString settingsPage;
- if (m_manager->checkDebugConfiguration(startParameters()->toolChainType, &errorMessage,
- &settingsCategory, &settingsPage)) {
- m_manager->startNewDebugger(m_startParameters);
+ if (m_manager->checkDebugConfiguration(m_startParameters.toolChainType,
+ &errorMessage, &settingsCategory, &settingsPage)) {
+ m_manager->startNewDebugger(this);
emit started();
} else {
appendMessage(this, errorMessage, true);
emit finished();
- Core::ICore::instance()->showWarningWithOptions(tr("Debugger"), errorMessage,
- QString(),
- settingsCategory, settingsPage);
+ Core::ICore::instance()->showWarningWithOptions(tr("Debugger"),
+ errorMessage, QString(), settingsCategory, settingsPage);
}
}
-void DebuggerRunControl::slotAddToOutputWindowInline(const QString &data,
- bool onStdErr)
+void DebuggerRunControl::showMessage(const QString &msg, int channel,
+ int timeout)
{
- emit addToOutputWindowInline(this, data, onStdErr);
+ if (!m_manager)
+ return;
+ DebuggerOutputWindow *ow = m_manager->debuggerOutputWindow();
+ QTC_ASSERT(ow, return);
+ switch (channel) {
+ case StatusBar:
+ m_manager->showStatusMessage(msg, timeout);
+ ow->showOutput(LogStatus, msg);
+ break;
+ case AppOutput:
+ emit addToOutputWindowInline(this, msg, false);
+ break;
+ case AppError:
+ emit addToOutputWindowInline(this, msg, true);
+ break;
+ case LogMiscInput:
+ ow->showInput(LogMisc, msg);
+ ow->showOutput(LogMisc, msg);
+ break;
+ case LogInput:
+ ow->showInput(channel, msg);
+ ow->showOutput(channel, msg);
+ break;
+ default:
+ ow->showOutput(channel, msg);
+ break;
+ }
}
void DebuggerRunControl::slotMessageAvailable(const QString &data, bool isError)
emit appendMessage(this, data, isError);
}
+
void DebuggerRunControl::stop()
{
m_running = false;
return m_running;
}
-} // namespace Internal
} // namespace Debugger
#ifndef DEBUGGERRUNNER_H
#define DEBUGGERRUNNER_H
-#include "debuggermanager.h"
#include "debugger_global.h"
+#include "debuggerconstants.h"
+
+#include <coreplugin/ssh/sshconnection.h>
#include <projectexplorer/runconfiguration.h>
-#include <projectexplorer/applicationrunconfiguration.h>
+
+#include <QtCore/QStringList>
+
+namespace ProjectExplorer {
+ class Environment;
+}
namespace Debugger {
-namespace Internal {
+
+class DebuggerManager;
+
+class DEBUGGER_EXPORT DebuggerStartParameters
+{
+public:
+ DebuggerStartParameters();
+ void clear();
+
+ QString executable;
+ QString displayName;
+ QString coreFile;
+ QStringList processArgs;
+ QStringList environment;
+ QString workingDirectory;
+ qint64 attachPID;
+ bool useTerminal;
+ QString crashParameter; // for AttachCrashedExternal
+ // for remote debugging
+ QString remoteChannel;
+ QString remoteArchitecture;
+ QString symbolFileName;
+ QString serverStartScript;
+ QString sysRoot;
+ QString debuggerCommand;
+ int toolChainType;
+ QByteArray remoteDumperLib;
+ QString qtInstallPath;
+
+ QString dumperLibrary;
+ QStringList dumperLibraryLocations;
+ Core::SshServerInfo sshserver;
+ DebuggerStartMode startMode;
+};
+
+//DEBUGGER_EXPORT QDebug operator<<(QDebug str, const DebuggerStartParameters &);
class DEBUGGER_EXPORT DebuggerRunControlFactory
: public ProjectExplorer::IRunControlFactory
virtual QWidget *createConfigurationWidget(ProjectExplorer::RunConfiguration *runConfiguration);
- ProjectExplorer::RunControl *create(const DebuggerStartParametersPtr &sp);
+ // This is used by the "Non-Standard" scenarios, e.g. Attach to Core.
+ ProjectExplorer::RunControl *create(const DebuggerStartParameters &sp);
private:
- DebuggerStartParametersPtr m_startParameters;
DebuggerManager *m_manager;
};
public:
DebuggerRunControl(DebuggerManager *manager,
- ProjectExplorer::LocalApplicationRunConfiguration *runConfiguration);
- DebuggerRunControl(DebuggerManager *manager, const DebuggerStartParametersPtr &startParameters);
+ const DebuggerStartParameters &startParameters);
void setCustomEnvironment(ProjectExplorer::Environment env);
virtual void start();
virtual void stop();
virtual bool isRunning() const;
+ QString displayName() const;
Q_SLOT void debuggingFinished();
- DebuggerStartParametersPtr startParameters() { return m_startParameters; }
+
+ const DebuggerStartParameters &sp() const { return m_startParameters; }
signals:
void stopRequested();
+public slots:
+ void showMessage(const QString &output, int channel = LogDebug, int timeout = -1);
+
private slots:
- void slotAddToOutputWindowInline(const QString &output, bool onStdErr);
void slotMessageAvailable(const QString &data, bool isError);
private:
void init();
- DebuggerStartParametersPtr m_startParameters;
+ DebuggerStartParameters m_startParameters;
DebuggerManager *m_manager;
bool m_running;
};
-} // namespace Internal
} // namespace Debugger
#endif // DEBUGGERRUNNER_H
#include "abstractgdbadapter.h"
+#include "abstractgdbprocess.h"
+
#include <utils/qtcassert.h>
#include <QtCore/QProcess>
void AbstractGdbAdapter::write(const QByteArray &data)
{
- m_engine->m_gdbProc.write(data);
+ gdbProc()->write(data);
}
bool AbstractGdbAdapter::isTrkAdapter() const
namespace Debugger {
namespace Internal {
+class AbstractGdbProcess;
+
// AbstractGdbAdapter is inherited by PlainGdbAdapter used for local
// debugging and TrkGdbAdapter used for on-device debugging.
// In the PlainGdbAdapter case it's just a wrapper around a QProcess running
virtual void interruptInferior() = 0;
virtual void shutdown();
virtual const char *inferiorShutdownCommand() const;
+ virtual AbstractGdbProcess *gdbProc() = 0;
virtual DumperHandling dumperHandling() const = 0;
{ m_engine->setState(state); }
const DebuggerStartParameters &startParameters() const
{ return m_engine->startParameters(); }
- void debugMessage(const QString &msg) const
- { m_engine->debugMessage(msg); }
- void showStatusMessage(const QString &msg) const
- { m_engine->showStatusMessage(msg); }
+ DebuggerRunControl *runControl() const
+ { return m_engine->runControl(); }
+ void showMessage(const QString &msg, int channel = LogDebug, int timeout = 1)
+ { runControl()->showMessage(msg, channel, timeout); }
void showMessageBox(int icon, const QString &title, const QString &text) const
{ m_engine->showMessageBox(icon, title, text); }
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "abstractgdbprocess.h"
+
+namespace Debugger {
+namespace Internal {
+
+} // namespace Internal
+} // namespace Debugger
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef GDBPROCESSWRAPPER_H
+#define GDBPROCESSWRAPPER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QProcess>
+
+namespace Debugger {
+namespace Internal {
+
+class AbstractGdbProcess : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(AbstractGdbProcess)
+public:
+ virtual QByteArray readAllStandardOutput() = 0;
+ virtual QByteArray readAllStandardError() = 0;
+
+ virtual void start(const QString &cmd, const QStringList &args) = 0;
+ virtual bool waitForStarted() = 0;
+ virtual qint64 write(const QByteArray &data) = 0;
+ virtual void kill() = 0;
+
+ virtual QProcess::ProcessState state() const = 0;
+ virtual QString errorString() const = 0;
+
+ virtual QProcessEnvironment processEnvironment() const = 0;
+ virtual void setProcessEnvironment(const QProcessEnvironment &env) = 0;
+ virtual void setEnvironment(const QStringList &env) = 0;
+ virtual void setWorkingDirectory(const QString &dir) = 0;
+
+ virtual ~AbstractGdbProcess() {}
+
+signals:
+ void error(QProcess::ProcessError);
+ void finished(int exitCode, QProcess::ExitStatus exitStatus);
+ void readyReadStandardError();
+ void readyReadStandardOutput();
+
+protected:
+ explicit AbstractGdbProcess(QObject *parent = 0) : QObject(parent) {}
+
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // GDBPROCESSWRAPPER_H
**
**************************************************************************/
-#include "plaingdbadapter.h"
+#include "abstractplaingdbadapter.h"
-#include "gdbengine.h"
-#include "procinterrupt.h"
-#include "debuggerstringutils.h"
#include "debuggeractions.h"
+#include "debuggerstringutils.h"
#include <utils/qtcassert.h>
-#include <QtCore/QFileInfo>
-
namespace Debugger {
namespace Internal {
#define CB(callback) \
- static_cast<GdbEngine::AdapterCallback>(&PlainGdbAdapter::callback), \
+ static_cast<GdbEngine::AdapterCallback>(&AbstractPlainGdbAdapter::callback), \
STRINGIFY(callback)
-///////////////////////////////////////////////////////////////////////
-//
-// PlainGdbAdapter
-//
-///////////////////////////////////////////////////////////////////////
-
-PlainGdbAdapter::PlainGdbAdapter(GdbEngine *engine, QObject *parent)
+AbstractPlainGdbAdapter::AbstractPlainGdbAdapter(GdbEngine *engine,
+ QObject *parent)
: AbstractGdbAdapter(engine, parent)
{
- // Output
- connect(&m_outputCollector, SIGNAL(byteDelivery(QByteArray)),
- engine, SLOT(readDebugeeOutput(QByteArray)));
}
-AbstractGdbAdapter::DumperHandling PlainGdbAdapter::dumperHandling() const
-{
- // LD_PRELOAD fails for System-Qt on Mac.
-#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
- return DumperLoadedByGdb;
-#else
- return DumperLoadedByGdbPreload;
-#endif
-}
-
-void PlainGdbAdapter::startAdapter()
-{
- QTC_ASSERT(state() == EngineStarting, qDebug() << state());
- setState(AdapterStarting);
- debugMessage(_("TRYING TO START ADAPTER"));
-
- QStringList gdbArgs;
-
- if (!m_outputCollector.listen()) {
- emit adapterStartFailed(tr("Cannot set up communication with child process: %1")
- .arg(m_outputCollector.errorString()), QString());
- return;
- }
- gdbArgs.append(_("--tty=") + m_outputCollector.serverName());
-
- if (!startParameters().workingDir.isEmpty())
- m_engine->m_gdbProc.setWorkingDirectory(startParameters().workingDir);
- if (!startParameters().environment.isEmpty())
- m_engine->m_gdbProc.setEnvironment(startParameters().environment);
-
- if (!m_engine->startGdb(gdbArgs)) {
- m_outputCollector.shutdown();
- return;
- }
-
- emit adapterStarted();
-}
-void PlainGdbAdapter::startInferior()
+void AbstractPlainGdbAdapter::startInferior()
{
QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
if (!startParameters().processArgs.isEmpty()) {
QString args = startParameters().processArgs.join(_(" "));
- m_engine->postCommand("-exec-arguments " + args.toLocal8Bit());
+ m_engine->postCommand("-exec-arguments " + toLocalEncoding(args));
}
- QFileInfo fi(startParameters().executable);
- QByteArray path = fi.absoluteFilePath().toLocal8Bit();
- m_engine->postCommand("-file-exec-and-symbols \"" + path + '"',
+ m_engine->postCommand("-file-exec-and-symbols \"" + execFilePath() + '"',
CB(handleFileExecAndSymbols));
}
-void PlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
+void AbstractPlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
{
QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
if (response.resultClass == GdbResultDone) {
-#ifdef Q_OS_LINUX
- // Old gdbs do not announce the PID for programs without pthreads.
- // Note that successfully preloading the debugging helpers will
- // automatically load pthreads, so this will be unnecessary.
- if (m_engine->m_gdbVersion < 70000)
- m_engine->postCommand("info target", CB(handleInfoTarget));
-#endif
+ if (infoTargetNecessary()) {
+ // Old gdbs do not announce the PID for programs without pthreads.
+ // Note that successfully preloading the debugging helpers will
+ // automatically load pthreads, so this will be unnecessary.
+ if (m_engine->m_gdbVersion < 70000)
+ m_engine->postCommand("info target", CB(handleInfoTarget));
+ }
emit inferiorPrepared();
} else {
QByteArray ba = response.data.findChild("msg").data();
- QString msg = QString::fromLocal8Bit(ba);
+ QString msg = fromLocalEncoding(ba);
// Extend the message a bit in unknown cases.
if (!ba.endsWith("File format not recognized"))
msg = tr("Starting executable failed:\n") + msg;
}
}
-#ifdef Q_OS_LINUX
-void PlainGdbAdapter::handleInfoTarget(const GdbResponse &response)
-{
- if (response.resultClass == GdbResultDone) {
- // [some leading stdout here]
- // >&" Entry point: 0x80831f0 0x08048134 - 0x08048147 is .interp\n"
- // [some trailing stdout here]
- QString msg = _(response.data.findChild("consolestreamoutput").data());
- QRegExp needle(_("\\bEntry point: 0x([0-9a-f]+)\\b"));
- if (needle.indexIn(msg) != -1) {
- m_engine->m_entryPoint =
- "0x" + needle.cap(1).toLatin1().rightJustified(sizeof(void *) * 2, '0');
- m_engine->postCommand("tbreak *0x" + needle.cap(1).toAscii());
- // Do nothing here - inferiorPrepared handles the sequencing.
- } else {
- emit inferiorStartFailed(_("Parsing start address failed"));
- }
- } else if (response.resultClass == GdbResultError) {
- emit inferiorStartFailed(_("Fetching start address failed"));
- }
-}
-#endif
-
-void PlainGdbAdapter::startInferiorPhase2()
+void AbstractPlainGdbAdapter::startInferiorPhase2()
{
setState(InferiorRunningRequested);
m_engine->postCommand("-exec-run", GdbEngine::RunRequest, CB(handleExecRun));
}
-void PlainGdbAdapter::handleExecRun(const GdbResponse &response)
+void AbstractPlainGdbAdapter::handleExecRun(const GdbResponse &response)
{
if (response.resultClass == GdbResultRunning) {
QTC_ASSERT(state() == InferiorRunning, qDebug() << state());
- debugMessage(_("INFERIOR STARTED"));
- showStatusMessage(msgInferiorStarted());
+ showMessage(_("INFERIOR STARTED"));
+ showMessage(msgInferiorStarted(), StatusBar);
// FIXME: That's the wrong place for it.
if (theDebuggerBoolSetting(EnableReverseDebugging))
m_engine->postCommand("target record");
} else {
QTC_ASSERT(state() == InferiorRunningRequested, qDebug() << state());
- QString msg = QString::fromLocal8Bit(response.data.findChild("msg").data());
+ QString msg = fromLocalEncoding(response.data.findChild("msg").data());
//QTC_ASSERT(status() == InferiorRunning, /**/);
//interruptInferior();
emit inferiorStartFailed(msg);
}
}
-void PlainGdbAdapter::interruptInferior()
+void AbstractPlainGdbAdapter::handleInfoTarget(const GdbResponse &response)
{
- const qint64 attachedPID = m_engine->inferiorPid();
- if (attachedPID <= 0) {
- debugMessage(_("TRYING TO INTERRUPT INFERIOR BEFORE PID WAS OBTAINED"));
- return;
+ if (response.resultClass == GdbResultDone) {
+ // [some leading stdout here]
+ // >&" Entry point: 0x80831f0 0x08048134 - 0x08048147 is .interp\n"
+ // [some trailing stdout here]
+ QString msg = _(response.data.findChild("consolestreamoutput").data());
+ QRegExp needle(_("\\bEntry point: 0x([0-9a-f]+)\\b"));
+ if (needle.indexIn(msg) != -1) {
+ m_engine->m_entryPoint =
+ "0x" + needle.cap(1).toLatin1().rightJustified(sizeof(void *) * 2, '0');
+ m_engine->postCommand("tbreak *0x" + needle.cap(1).toAscii());
+ // Do nothing here - inferiorPrepared handles the sequencing.
+ } else {
+ emit inferiorStartFailed(_("Parsing start address failed"));
+ }
+ } else if (response.resultClass == GdbResultError) {
+ emit inferiorStartFailed(_("Fetching start address failed"));
}
-
- if (!interruptProcess(attachedPID))
- debugMessage(_("CANNOT INTERRUPT %1").arg(attachedPID));
}
-void PlainGdbAdapter::shutdown()
-{
- debugMessage(_("PLAIN ADAPTER SHUTDOWN %1").arg(state()));
- m_outputCollector.shutdown();
-}
-
-} // namespace Internal
} // namespace Debugger
+} // namespace Internal
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ABSTRACTPLAINGDBADAPTER_H
+#define ABSTRACTPLAINGDBADAPTER_H
+
+#include "abstractgdbadapter.h"
+
+namespace Debugger {
+namespace Internal {
+
+class AbstractPlainGdbAdapter : public AbstractGdbAdapter
+{
+public:
+ AbstractPlainGdbAdapter(GdbEngine *engine, QObject *parent = 0);
+
+ virtual void startInferior();
+ virtual void startInferiorPhase2();
+
+protected:
+ void handleInfoTarget(const GdbResponse &response);
+
+private:
+ virtual QByteArray execFilePath() const = 0;
+ virtual bool infoTargetNecessary() const = 0;
+ virtual QByteArray toLocalEncoding(const QString &s) const = 0;
+ virtual QString fromLocalEncoding(const QByteArray &b) const = 0;
+ void handleExecRun(const GdbResponse &response);
+ void handleFileExecAndSymbols(const GdbResponse &response);
+
+};
+
+} // namespace Debugger
+} // namespace Internal
+
+#endif // ABSTRACTPLAINGDBADAPTER_H
{
QTC_ASSERT(state() == EngineStarting, qDebug() << state());
setState(AdapterStarting);
- debugMessage(_("TRYING TO START ADAPTER"));
+ showMessage(_("TRYING TO START ADAPTER"));
if (!m_engine->startGdb())
return;
QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
if (response.resultClass == GdbResultDone) {
setState(InferiorStopped);
- debugMessage(_("INFERIOR ATTACHED"));
- showStatusMessage(msgAttachedToStoppedInferior());
+ showMessage(_("INFERIOR ATTACHED"));
+ showMessage(msgAttachedToStoppedInferior(), StatusBar);
emit inferiorPrepared();
m_engine->updateAll();
} else {
const qint64 pid = startParameters().attachPID;
QTC_ASSERT(pid > 0, return);
if (!interruptProcess(pid))
- debugMessage(_("CANNOT INTERRUPT %1").arg(pid));
+ showMessage(_("CANNOT INTERRUPT %1").arg(pid));
}
} // namespace Internal
#include "abstractgdbadapter.h"
+#include "abstractgdbprocess.h"
+
namespace Debugger {
namespace Internal {
void startInferior();
void interruptInferior();
const char *inferiorShutdownCommand() const { return "detach"; }
+ AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
private:
void handleAttach(const GdbResponse &response);
+
+ LocalGdbProcess m_gdbProc;
};
} // namespace Internal
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
+#include <QtGui/QMessageBox>
#if !defined(Q_OS_WIN)
#include <dlfcn.h>
// Avoid endless loops created by faulty dumpers.
QByteArray processedName = QByteArray::number(dumpChildren) + '-' + data.iname;
if (m_processedNames.contains(processedName)) {
- showDebuggerInput(LogStatus,
- _("<Breaking endless loop for " + data.iname + '>'));
+ showMessage(
+ _("<Breaking endless loop for " + data.iname + '>'), LogMiscInput);
data.setAllUnneeded();
data.setValue(_("<unavailable>"));
data.setHasChildren(false);
{
PRECONDITION;
WatchData data = data0;
- #if DEBUG_SUBITEM
+# if DEBUG_SUBITEM
qDebug() << "UPDATE SUBITEM:" << data.toString();
- #endif
+# endif
QTC_ASSERT(data.isValid(), return);
// in any case we need the type first
// Let's play safe, though.
if (!data.variable.isEmpty()) {
// Update: It does so for out-of-scope watchers.
- #if 1
+# if 1
qDebug() << "FIXME: GdbEngine::updateSubItem:"
<< data.toString() << "should not happen";
- #else
+# else
data.setType(WatchData::msgNotInScope());
data.setValue(WatchData::msgNotInScope());
data.setHasChildren(false);
insertData(data);
return;
- #endif
+# endif
}
// The WatchVarCreate handler will receive type information
// and re-insert a WatchData item with correct type, so
if (data.isChildrenNeeded() && isPointerType(data.type)
&& !hasDebuggingHelperForType(data.type)) {
// We sometimes know what kind of children pointers have
- #if DEBUG_SUBITEM
+# if DEBUG_SUBITEM
qDebug() << "IT'S A POINTER";
- #endif
+# endif
if (theDebuggerBoolSetting(AutoDerefPointers)) {
// Try automatic dereferentiation
}
if (data.isValueNeeded() && hasDebuggingHelperForType(data.type)) {
- #if DEBUG_SUBITEM
+# if DEBUG_SUBITEM
qDebug() << "UPDATE SUBITEM: CUSTOMVALUE";
- #endif
+# endif
runDebuggingHelperClassic(data,
manager()->watchHandler()->isExpandedIName(data.iname));
return;
/*
if (data.isValueNeeded() && data.exp.isEmpty()) {
- #if DEBUG_SUBITEM
+# if DEBUG_SUBITEM
qDebug() << "UPDATE SUBITEM: NO EXPRESSION?";
- #endif
+# endif
data.setError("<no expression given>");
insertData(data);
return;
*/
if (data.isValueNeeded() && data.variable.isEmpty()) {
- #if DEBUG_SUBITEM
+# if DEBUG_SUBITEM
qDebug() << "UPDATE SUBITEM: VARIABLE NEEDED FOR VALUE";
- #endif
+# endif
createGdbVariableClassic(data);
// the WatchVarCreate handler will re-insert a WatchData
// item, with valueNeeded() set.
if (data.isValueNeeded()) {
QTC_ASSERT(!data.variable.isEmpty(), return); // tested above
- #if DEBUG_SUBITEM
+# if DEBUG_SUBITEM
qDebug() << "UPDATE SUBITEM: VALUE";
- #endif
+# endif
QByteArray cmd = "-var-evaluate-expression \"" + data.iname + '"';
postCommand(cmd, WatchUpdate,
CB(handleEvaluateExpressionClassic), QVariant::fromValue(data));
}
if (data.isChildrenNeeded() && hasDebuggingHelperForType(data.type)) {
- #if DEBUG_SUBITEM
+# if DEBUG_SUBITEM
qDebug() << "UPDATE SUBITEM: CUSTOMVALUE WITH CHILDREN";
- #endif
+# endif
runDebuggingHelperClassic(data, true);
return;
}
if (data.isChildrenNeeded() && data.variable.isEmpty()) {
- #if DEBUG_SUBITEM
+# if DEBUG_SUBITEM
qDebug() << "UPDATE SUBITEM: VARIABLE NEEDED FOR CHILDREN";
- #endif
+# endif
createGdbVariableClassic(data);
// the WatchVarCreate handler will re-insert a WatchData
// item, with childrenNeeded() set.
}
if (data.isHasChildrenNeeded() && hasDebuggingHelperForType(data.type)) {
- #if DEBUG_SUBITEM
+# if DEBUG_SUBITEM
qDebug() << "UPDATE SUBITEM: CUSTOMVALUE WITH CHILDREN";
- #endif
+# endif
runDebuggingHelperClassic(data,
manager()->watchHandler()->isExpandedIName(data.iname));
return;
//#if !X
if (data.isHasChildrenNeeded() && data.variable.isEmpty()) {
- #if DEBUG_SUBITEM
+# if DEBUG_SUBITEM
qDebug() << "UPDATE SUBITEM: VARIABLE NEEDED FOR CHILDCOUNT";
- #endif
+# endif
createGdbVariableClassic(data);
// the WatchVarCreate handler will re-insert a WatchData
// item, with childrenNeeded() set.
// Remove traces of the question, too.
if (m_cookieForToken.contains(response.token - 1)) {
m_cookieForToken.remove(response.token - 1);
- debugMessage(_("DETECTING LOST COMMAND %1").arg(response.token - 1));
+ showMessage(_("DETECTING LOST COMMAND %1").arg(response.token - 1));
--m_pendingWatchRequests;
data.setError(WatchData::msgNotInScope());
insertData(data);
m_debuggingHelperState = DebuggingHelperLoadTried;
QByteArray dlopenLib;
- if (startParameters().startMode == StartRemote)
- dlopenLib = startParameters().remoteDumperLib.toLocal8Bit();
+ if (runControl()->sp().startMode == AttachToRemote
+ || runControl()->sp().startMode == StartRemoteGdb)
+ dlopenLib = runControl()->sp().remoteDumperLib;
else
dlopenLib = manager()->qtDumperLibraryName().toLocal8Bit();
QVariant::fromValue<StackCookie>(StackCookie(false, true)));
manager()->stackHandler()->setCurrentIndex(0);
if (supportsThreads())
- postCommand("-thread-list-ids", WatchUpdate, CB(handleStackListThreads), 0);
+ postCommand("-thread-list-ids", WatchUpdate, CB(handleThreadListIds), 0);
manager()->reloadRegisters();
updateLocals();
}
{
PRECONDITION;
if (on.toBool()) {
- debugMessage(_("SWITCHING ON DUMPER DEBUGGING"));
+ showMessage(_("SWITCHING ON DUMPER DEBUGGING"));
postCommand("set unwindonsignal off");
m_manager->breakByFunction(_("qDumpObjectData440"));
//updateLocals();
} else {
- debugMessage(_("SWITCHING OFF DUMPER DEBUGGING"));
+ showMessage(_("SWITCHING OFF DUMPER DEBUGGING"));
postCommand("set unwindonsignal on");
}
}
} else {
// Seems to occur on "RedHat 4 based Linux" gdb 7.0.1:
// ^error,msg="Cannot access memory at address 0x0"
- debugMessage(_("UNEXPECTED RESPONSE: ") + response.toString());
+ showMessage(_("UNEXPECTED RESPONSE: ") + response.toString());
}
}
if (data.isValid())
list.push_back(data);
}
+
+ if (!m_resultVarName.isEmpty()) {
+ WatchData rd;
+ rd.iname = "return.0";
+ rd.name = "return";
+ rd.exp = m_resultVarName;
+ list.append(rd);
+ }
+
manager()->watchHandler()->insertBulkData(list);
manager()->watchHandler()->updateWatchers();
}
const QStringList &locations = manager()->qtDumperLibraryLocations();
const QString loc = locations.join(QLatin1String(", "));
const QString msg = tr("The debugging helper library was not found at %1.").arg(loc);
- debugMessage(msg);
+ showMessage(msg);
manager()->showQtDumperLibraryWarning(msg);
return false;
}
const QString successMsg = tr("Dumper version %1, %n custom dumpers found.",
0, m_dumperHelper.typeCount()).arg(dumperVersion);
showStatusMessage(successMsg);
+
+ // Sanity check for Qt version of dumpers and debuggee.
+ QByteArray ns = m_dumperHelper.qtNamespace().toLatin1();
+ postCommand("-var-create A@ * '" + ns + "qVersion'()",
+ CB(handleDebuggingHelperVersionCheckClassic));
+ postCommand("-var-delete A@");
} else {
// Retry if thread has not terminated yet.
m_debuggingHelperState = DebuggingHelperUnavailable;
//qDebug() << m_availableSimpleDebuggingHelpers << "DATA DUMPERS AVAILABLE";
}
+void GdbEngine::handleDebuggingHelperVersionCheckClassic(const GdbResponse &response)
+{
+ if (response.resultClass == GdbResultDone) {
+ QString value = _(response.data.findChild("value").data());
+ QString debuggeeQtVersion = value.section(QLatin1Char('"'), 1, 1);
+ QString dumperQtVersion = m_dumperHelper.qtVersionString();
+ if (dumperQtVersion != debuggeeQtVersion) {
+ manager()->showMessageBox(QMessageBox::Warning,
+ tr("Debugging helpers: Qt version mismatch"),
+ tr("The Qt version used to build the debugging helpers (%1) "
+ "does not match the Qt version used to build the debugged "
+ "application (%2).\nThis might yield incorrect results.")
+ .arg(dumperQtVersion).arg(debuggeeQtVersion));
+ } else {
+ showMessage(_("DUMPER VERSION CHECK SUCCESSFUL: ")
+ + dumperQtVersion);
+ }
+ } else {
+ showMessage("DUMPER VERSION CHECK NOT COMPLETED");
+ }
+}
+
void GdbEngine::handleVarListChildrenHelperClassic(const GdbMi &item,
const WatchData &parent)
{
{
QTC_ASSERT(state() == EngineStarting, qDebug() << state());
setState(AdapterStarting);
- debugMessage(_("TRYING TO START ADAPTER"));
+ showMessage(_("TRYING TO START ADAPTER"));
if (!m_engine->startGdb())
return;
{
QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
if (response.resultClass == GdbResultDone) {
- showStatusMessage(tr("Symbols found."));
+ showMessage(tr("Symbols found."), StatusBar);
} else {
QString msg = tr("Loading symbols from \"%1\" failed:\n").arg(m_executable)
+ QString::fromLocal8Bit(response.data.findChild("msg").data());
.absoluteFilePath(m_executable);
if (QFile::exists(m_executable)) {
// Finish extra round ...
- showStatusMessage(tr("Attached to core temporarily."));
+ showMessage(tr("Attached to core temporarily."), StatusBar);
m_engine->postCommand("detach");
// ... and retry.
loadExeAndSyms();
tr("Unable to determine executable from core file."));
}
#endif
- showStatusMessage(tr("Attached to core."));
+ showMessage(tr("Attached to core."), StatusBar);
setState(InferiorUnrunnable);
m_engine->updateAll();
} else {
#include "abstractgdbadapter.h"
+#include "abstractgdbprocess.h"
+
#ifdef Q_OS_LINUX
# define EXE_FROM_CORE
#endif
void startAdapter();
void startInferior();
void interruptInferior();
+ AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
private:
void loadExeAndSyms();
int m_round;
#endif
QString m_executable;
+ LocalGdbProcess m_gdbProc;
};
} // namespace Internal
$$PWD/abstractgdbadapter.h \
$$PWD/attachgdbadapter.h \
$$PWD/coregdbadapter.h \
- $$PWD/plaingdbadapter.h \
+ $$PWD/localplaingdbadapter.h \
$$PWD/termgdbadapter.h \
- $$PWD/remotegdbadapter.h \
+ $$PWD/remotegdbserveradapter.h \
$$PWD/trkgdbadapter.h \
- $$PWD/s60debuggerbluetoothstarter.h
+ $$PWD/s60debuggerbluetoothstarter.h \
+ $$PWD/abstractgdbprocess.h \
+ $$PWD/localgdbprocess.h \
+ $$PWD/remotegdbprocess.h \
+ $$PWD/remoteplaingdbadapter.h \
+ $$PWD/abstractplaingdbadapter.h
SOURCES += \
$$PWD/gdbmi.cpp \
$$PWD/abstractgdbadapter.cpp \
$$PWD/attachgdbadapter.cpp \
$$PWD/coregdbadapter.cpp \
- $$PWD/plaingdbadapter.cpp \
+ $$PWD/localplaingdbadapter.cpp \
$$PWD/termgdbadapter.cpp \
- $$PWD/remotegdbadapter.cpp \
+ $$PWD/remotegdbserveradapter.cpp \
$$PWD/trkgdbadapter.cpp \
- $$PWD/s60debuggerbluetoothstarter.cpp
+ $$PWD/s60debuggerbluetoothstarter.cpp \
+ $$PWD/abstractgdbprocess.cpp \
+ $$PWD/localgdbprocess.cpp \
+ $$PWD/remotegdbprocess.cpp \
+ $$PWD/remoteplaingdbadapter.cpp \
+ $$PWD/abstractplaingdbadapter.cpp
FORMS += $$PWD/gdboptionspage.ui
#include "attachgdbadapter.h"
#include "coregdbadapter.h"
-#include "plaingdbadapter.h"
+#include "localplaingdbadapter.h"
#include "termgdbadapter.h"
-#include "remotegdbadapter.h"
+#include "remotegdbserveradapter.h"
+#include "remoteplaingdbadapter.h"
#include "trkgdbadapter.h"
#include "watchutils.h"
#include "registerhandler.h"
#include "snapshothandler.h"
#include "stackhandler.h"
+#include "threadshandler.h"
#include "watchhandler.h"
#include "sourcefileswindow.h"
DebuggerStartMode GdbEngine::startMode() const
{
- QTC_ASSERT(!m_startParameters.isNull(), return NoStartMode);
- return m_startParameters->startMode;
+ QTC_ASSERT(m_runControl, return NoStartMode);
+ return startParameters().startMode;
}
QMainWindow *GdbEngine::mainWindow() const
return DebuggerUISwitcher::instance()->mainWindow();
}
+AbstractGdbProcess *GdbEngine::gdbProc() const
+{
+ return m_gdbAdapter->gdbProc();
+}
+
GdbEngine::~GdbEngine()
{
// Prevent sending error messages afterwards.
- disconnect(&m_gdbProc, 0, this, 0);
+ if (m_gdbAdapter)
+ disconnect(gdbProc(), 0, this, 0);
delete m_gdbAdapter;
m_gdbAdapter = 0;
}
m_pendingLogStreamOutput.clear();
m_inbuffer.clear();
+ m_resultVarName.clear();
m_commandTimer->stop();
data.constData(), data.length(), &m_outputCodecState), true);
}
-void GdbEngine::debugMessage(const QString &msg)
-{
- showDebuggerOutput(LogDebug, msg);
-}
-
void GdbEngine::handleResponse(const QByteArray &buff)
{
static QTime lastTime;
if (theDebuggerBoolSetting(LogTimeStamps))
- showDebuggerOutput(LogTime, currentTime());
- showDebuggerOutput(LogOutput, QString::fromLocal8Bit(buff, buff.length()));
+ showMessage(currentTime(), LogTime);
+ showMessage(QString::fromLocal8Bit(buff, buff.length()), LogOutput);
#if 0
qDebug() // << "#### start response handling #### "
int progress = m_progress->progressValue();
m_progress->setProgressValue(qMin(70, progress + 1));
QByteArray id = result.findChild("id").data();
- showStatusMessage(tr("Thread group %1 created.").arg(_(id)), 1000);
+ showStatusMessage(tr("Thread group %1 created").arg(_(id)), 1000);
int pid = id.toInt();
if (pid != inferiorPid())
handleInferiorPidChanged(pid);
const GdbMi bkpt = result.findChild("bkpt");
const int number = bkpt.findChild("number").data().toInt();
BreakHandler *handler = manager()->breakHandler();
- BreakpointData *data = handler->findBreakpoint(number);
- breakpointDataFromOutput(data, bkpt);
+ BreakpointData *data = handler->findBreakpointByNumber(number);
+ setBreakpointDataFromOutput(data, bkpt);
handler->updateMarkers();
} else {
qDebug() << "IGNORED ASYNC OUTPUT"
void GdbEngine::readGdbStandardError()
{
- QByteArray err = m_gdbProc.readAllStandardError();
- debugMessage(_("UNEXPECTED GDB STDERR: " + err));
+ QByteArray err = gdbProc()->readAllStandardError();
+ showMessage(_("UNEXPECTED GDB STDERR: " + err));
if (err == "Undefined command: \"bb\". Try \"help\".\n")
return;
if (err.startsWith("BFD: reopening"))
int newstart = 0;
int scan = m_inbuffer.size();
- m_inbuffer.append(m_gdbProc.readAllStandardOutput());
+ m_inbuffer.append(gdbProc()->readAllStandardOutput());
// This can trigger when a dialog starts a nested event loop
if (m_busy)
scan = newstart;
if (end == start)
continue;
- #if defined(Q_OS_WIN)
+# if defined(Q_OS_WIN)
if (m_inbuffer.at(end - 1) == '\r') {
--end;
if (end == start)
continue;
}
- #endif
+# endif
m_busy = true;
handleResponse(QByteArray::fromRawData(m_inbuffer.constData() + start, end - start));
m_busy = false;
setState(InferiorStopping);
showStatusMessage(tr("Stop requested..."), 5000);
- debugMessage(_("TRYING TO INTERRUPT INFERIOR"));
+ showMessage(_("TRYING TO INTERRUPT INFERIOR"));
m_gdbAdapter->interruptInferior();
}
{
const qint64 pid = pid0.toLongLong();
if (pid == 0) {
- debugMessage(_("Cannot parse PID from %1").arg(pid0));
+ showMessage(_("Cannot parse PID from %1").arg(pid0));
return;
}
if (pid == inferiorPid())
return;
- debugMessage(_("FOUND PID %1").arg(pid));
+ showMessage(_("FOUND PID %1").arg(pid));
handleInferiorPidChanged(pid);
}
{
if (!stateAcceptsGdbCommands(state())) {
PENDING_DEBUG(_("NO GDB PROCESS RUNNING, CMD IGNORED: " + cmd.command));
- debugMessage(_("NO GDB PROCESS RUNNING, CMD IGNORED: %1 %2")
+ showMessage(_("NO GDB PROCESS RUNNING, CMD IGNORED: %1 %2")
.arg(_(cmd.command)).arg(state()));
return;
}
flushCommand(cmd);
} else {
// Queue the commands that we cannot send at once.
- debugMessage(_("QUEUING COMMAND " + cmd.command));
+ showMessage(_("QUEUING COMMAND " + cmd.command));
m_commandsToRunOnTemporaryBreak.append(cmd);
if (state() == InferiorStopping) {
if (cmd.flags & LosesChild)
setState(InferiorStopping_Kill);
- debugMessage(_("CHILD ALREADY BEING INTERRUPTED. STILL HOPING."));
+ showMessage(_("CHILD ALREADY BEING INTERRUPTED. STILL HOPING."));
// Calling shutdown() here breaks all situations where two
// NeedsStop commands are issued in quick succession.
} else if (state() == InferiorStopping_Kill) {
- debugMessage(_("CHILD ALREADY BEING INTERRUPTED (KILL PENDING)"));
+ showMessage(_("CHILD ALREADY BEING INTERRUPTED (KILL PENDING)"));
// FIXME
shutdown();
} else if (state() == InferiorRunningRequested) {
if (cmd.flags & LosesChild)
setState(InferiorRunningRequested_Kill);
- debugMessage(_("RUNNING REQUESTED; POSTPONING INTERRUPT"));
+ showMessage(_("RUNNING REQUESTED; POSTPONING INTERRUPT"));
} else if (state() == InferiorRunningRequested_Kill) {
- debugMessage(_("RUNNING REQUESTED; POSTPONING INTERRUPT (KILL PENDING)"));
+ showMessage(_("RUNNING REQUESTED; POSTPONING INTERRUPT (KILL PENDING)"));
} else if (state() == InferiorRunning) {
- showStatusMessage(tr("Stopping temporarily."), 1000);
+ showStatusMessage(tr("Stopping temporarily"), 1000);
interruptInferiorTemporarily();
} else {
qDebug() << "ATTEMPTING TO QUEUE COMMAND IN INAPPROPRIATE STATE" << state();
void GdbEngine::flushQueuedCommands()
{
- showStatusMessage(tr("Processing queued commands."), 1000);
+ showStatusMessage(tr("Processing queued commands"), 1000);
while (!m_commandsToRunOnTemporaryBreak.isEmpty()) {
GdbCommand cmd = m_commandsToRunOnTemporaryBreak.takeFirst();
- debugMessage(_("RUNNING QUEUED COMMAND " + cmd.command + ' '
+ showMessage(_("RUNNING QUEUED COMMAND " + cmd.command + ' '
+ cmd.callbackName));
flushCommand(cmd);
}
{
GdbCommand cmd = cmd0;
if (state() == DebuggerNotReady) {
- showDebuggerInput(LogInput, _(cmd.command));
- debugMessage(_("GDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: " + cmd.command));
+ showMessage(_(cmd.command), LogInput);
+ showMessage(_("GDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: " + cmd.command));
return;
}
cmd.postTime = QTime::currentTime();
m_cookieForToken[currentToken()] = cmd;
cmd.command = QByteArray::number(currentToken()) + cmd.command;
- showDebuggerInput(LogInput, _(cmd.command));
+ showMessage(_(cmd.command), LogInput);
m_gdbAdapter->write(cmd.command + "\r\n");
msg += ": " + cmd.command + " => ";
QTC_ASSERT(cmd.callbackName, /**/);
msg += cmd.callbackName;
- debugMessage(_(msg));
+ showMessage(_(msg));
}
if (killIt) {
- debugMessage(_("TIMED OUT WAITING FOR GDB REPLY. COMMANDS STILL IN PROGRESS:"));
+ showMessage(_("TIMED OUT WAITING FOR GDB REPLY. COMMANDS STILL IN PROGRESS:"));
int timeOut = m_commandTimer->interval();
//m_commandTimer->stop();
const QString msg = tr("The gdb process has not responded "
mb->button(QMessageBox::Cancel)->setText(tr("Give gdb more time"));
mb->button(QMessageBox::Ok)->setText(tr("Stop debugging"));
if (mb->exec() == QMessageBox::Ok) {
- debugMessage(_("KILLING DEBUGGER AS REQUESTED BY USER"));
+ showMessage(_("KILLING DEBUGGER AS REQUESTED BY USER"));
// This is an undefined state, so we just pull the emergency brake.
manager()->watchHandler()->endCycle();
- m_gdbProc.kill();
+ gdbProc()->kill();
} else {
- debugMessage(_("CONTINUE DEBUGGER AS REQUESTED BY USER"));
+ showMessage(_("CONTINUE DEBUGGER AS REQUESTED BY USER"));
}
} else {
- debugMessage(_("\nNON-CRITICAL TIMEOUT\n"));
+ showMessage(_("\nNON-CRITICAL TIMEOUT\n"));
}
}
// reported in the "first" response to the command) in practice it
// does. We try to handle a few situations we are aware of gracefully.
// Ideally, this code should not be present at all.
- debugMessage(_("COOKIE FOR TOKEN %1 ALREADY EATEN. "
+ showMessage(_("COOKIE FOR TOKEN %1 ALREADY EATEN. "
"TWO RESPONSES FOR ONE COMMAND?").arg(token));
if (response->resultClass == GdbResultError) {
QByteArray msg = response->data.findChild("msg").data();
// Handle a case known to occur on Linux/gdb 6.8 when debugging moc
// with helpers enabled. In this case we get a second response with
// msg="Cannot find new threads: generic error"
- debugMessage(_("APPLYING WORKAROUND #1"));
+ showMessage(_("APPLYING WORKAROUND #1"));
showMessageBox(QMessageBox::Critical,
tr("Executable failed"), QString::fromLocal8Bit(msg));
- showStatusMessage(tr("Process failed to start."));
+ showStatusMessage(tr("Process failed to start"));
shutdown();
} else if (msg == "\"finish\" not meaningful in the outermost frame.") {
// Handle a case known to appear on gdb 6.4 symbianelf when
// the stack is cut due to access to protected memory.
- debugMessage(_("APPLYING WORKAROUND #2"));
+ showMessage(_("APPLYING WORKAROUND #2"));
setState(InferiorStopping);
setState(InferiorStopped);
} else if (msg.startsWith("Cannot find bounds of current function")) {
// Happens when running "-exec-next" in a function for which
// there is no debug information. Divert to "-exec-next-step"
- debugMessage(_("APPLYING WORKAROUND #3"));
+ showMessage(_("APPLYING WORKAROUND #3"));
setState(InferiorStopping);
setState(InferiorStopped);
executeNextI();
// Happens on archer-tromey-python 6.8.50.20090910-cvs
// There might to be a race between a process shutting down
// and library load messages.
- debugMessage(_("APPLYING WORKAROUND #4"));
+ showMessage(_("APPLYING WORKAROUND #4"));
setState(InferiorStopping);
setState(InferiorStopped);
setState(InferiorShuttingDown);
GdbCommand cmd = m_cookieForToken.take(token);
if (theDebuggerBoolSetting(LogTimeStamps)) {
- showDebuggerOutput(LogTime, _("Response time: %1: %2 s")
+ showMessage(_("Response time: %1: %2 s")
.arg(_(cmd.command))
- .arg(cmd.postTime.msecsTo(QTime::currentTime()) / 1000.));
+ .arg(cmd.postTime.msecsTo(QTime::currentTime()) / 1000.),
+ LogTime);
}
if (response->token < m_oldestAcceptableToken && (cmd.flags & Discardable)) {
- //debugMessage(_("### SKIPPING OLD RESULT") + response.toString());
+ //showMessage(_("### SKIPPING OLD RESULT") + response.toString());
return;
}
GdbResultDone)) {
#ifdef Q_OS_WIN
// Ignore spurious 'running' responses to 'attach'
- const bool warning = !(m_startParameters->startMode == AttachExternal
+ const bool warning = !(manager()->runControl()->sp().startMode == AttachExternal
&& cmd.command.startsWith("attach"));
#else
const bool warning = true;
QByteArray rsp = GdbResponse::stringFromResultClass(response->resultClass);
rsp = "UNEXPECTED RESPONSE '" + rsp + "' TO COMMAND '" + cmd.command + "'";
qWarning() << rsp << " AT " __FILE__ ":" STRINGIFY(__LINE__);
- debugMessage(_(rsp));
+ showMessage(_(rsp));
}
} else {
if (cmd.callback)
// event loop is entered, and let individual commands have a flag to suppress
// that behavior.
if (m_commandsDoneCallback && m_cookieForToken.isEmpty()) {
- debugMessage(_("ALL COMMANDS DONE; INVOKING CALLBACK"));
+ showMessage(_("ALL COMMANDS DONE; INVOKING CALLBACK"));
CommandsDoneCallback cont = m_commandsDoneCallback;
m_commandsDoneCallback = 0;
(this->*cont)();
void GdbEngine::executeDebuggerCommand(const QString &command)
{
if (state() == DebuggerNotReady) {
- debugMessage(_("GDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command);
+ showMessage(_("GDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command);
return;
}
// ~"242\t x *= 2;"
//109^done"
setState(InferiorStopped);
- showStatusMessage(tr("Jumped. Stopped."));
+ showStatusMessage(tr("Jumped. Stopped"));
QByteArray output = response.data.findChild("logstreamoutput").data();
if (output.isEmpty())
return;
// // file="main.cpp",fullname="/tmp/g/main.cpp",line="37"}
// QTC_ASSERT(state() == InferiorStopping, qDebug() << state())
// setState(InferiorStopped);
-// showStatusMessage(tr("Function reached. Stopped."));
+// showStatusMessage(tr("Function reached. Stopped"));
// GdbMi frame = response.data.findChild("frame");
// StackFrame f = parseStackFrame(frame, 0);
// gotoLocation(f, true);
tryLoadDebuggingHelpers();
- #ifndef Q_OS_MAC
+# ifndef Q_OS_MAC
// intentionally after tryLoadDebuggingHelpers(),
// otherwise we'd interrupt solib loading.
if (theDebuggerBoolSetting(AllPluginBreakpoints)) {
postCommand("set auto-solib-add off");
postCommand("set stop-on-solib-events 0");
}
- #endif
+# endif
// It's nicer to see a bit of the world we live in.
reloadModulesInternal();
// The related code (handleAqcuiredInferior()) is disabled as well.
if (theDebuggerBoolSetting(SelectedPluginBreakpoints)) {
QString dataStr = _(data.toString());
- debugMessage(_("SHARED LIBRARY EVENT: ") + dataStr);
+ showMessage(_("SHARED LIBRARY EVENT: ") + dataStr);
QString pat = theDebuggerStringSetting(SelectedPluginBreakpointsPattern);
- debugMessage(_("PATTERN: ") + pat);
+ showMessage(_("PATTERN: ") + pat);
postCommand("sharedlibrary " + pat.toLocal8Bit());
showStatusMessage(tr("Loading %1...").arg(dataStr));
}
}
#endif
+ // FIXME: Replace the #ifdef by the "target" architecture
#ifdef Q_OS_LINUX
if (!m_entryPoint.isEmpty()) {
GdbMi frameData = data.findChild("frame");
}
#endif
- // seen on XP after removing a breakpoint while running
+ // This was seen on XP after removing a breakpoint while running
// >945*stopped,reason="signal-received",signal-name="SIGTRAP",
// signal-meaning="Trace/breakpoint trap",thread-id="2",
// frame={addr="0x7c91120f",func="ntdll!DbgUiConnectToDbg",
if (theDebuggerBoolSetting(SkipKnownFrames)) {
if (reason == "end-stepping-range" || reason == "function-finished") {
GdbMi frame = data.findChild("frame");
- //debugMessage(frame.toString());
+ //showMessage(frame.toString());
QString funcName = _(frame.findChild("func").data());
QString fileName = QString::fromLocal8Bit(frame.findChild("file").data());
if (isLeavableFunction(funcName, fileName)) {
- //debugMessage(_("LEAVING ") + funcName);
+ //showMessage(_("LEAVING ") + funcName);
++stepCounter;
m_manager->executeStepOut();
return;
}
if (isSkippableFunction(funcName, fileName)) {
- //debugMessage(_("SKIPPING ") + funcName);
+ //showMessage(_("SKIPPING ") + funcName);
++stepCounter;
m_manager->executeStep();
return;
}
}
+ // Show return value if possible, usually with reason "function-finished".
+ // *stopped,reason="function-finished",frame={addr="0x080556da",
+ // func="testReturnValue",args=[],file="/../app.cpp",
+ // fullname="/../app.cpp",line="1611"},gdb-result-var="$1",
+ // return-value="{d = 0x808d998}",thread-id="1",stopped-threads="all",
+ // core="1"
+ GdbMi resultVar = data.findChild("gdb-result-var");
+ if (resultVar.isValid())
+ m_resultVarName = resultVar.data();
+ else
+ m_resultVarName.clear();
+
bool initHelpers = m_debuggingHelperState == DebuggingHelperUninitialized
|| m_debuggingHelperState == DebuggingHelperLoadTried;
// Don't load helpers on stops triggered by signals unless it's
&& reason == "signal-received") {
QByteArray name = data.findChild("signal-name").data();
if (name != STOP_SIGNAL
- && (startParameters().startMode != StartRemote
+ && (runControl()->sp().startMode != AttachToRemote
|| name != CROSS_STOP_SIGNAL))
initHelpers = false;
}
&& reason == "signal-received"
&& data.findChild("signal-name").data() == "SIGTRAP") {
// Caused by "library load" message.
- debugMessage(_("INTERNAL CONTINUE"));
+ showMessage(_("INTERNAL CONTINUE"));
continueInferiorInternal();
return;
}
reloadBreakListInternal();
}
- if (reason == "breakpoint-hit") {
+ if (reason == "watchpoint-trigger") {
+ // *stopped,reason="watchpoint-trigger",wpt={number="2",exp="*0xbfffed40"},
+ // value={old="1",new="0"},frame={addr="0x00451e1b",
+ // func="QScopedPointer",args=[{name="this",value="0xbfffed40"},
+ // {name="p",value="0x0"}],file="x.h",fullname="/home/.../x.h",line="95"},
+ // thread-id="1",stopped-threads="all",core="2"
+ GdbMi wpt = data.findChild("wpt");
+ QByteArray bpNumber = wpt.findChild("number").data();
+ QByteArray bpAddress = wpt.findChild("exp").data();
+ //QByteArray threadId = data.findChild("thread-id").data();
+ showStatusMessage(tr("Watchpoint %1 at %2 triggered:")
+ .arg(_(bpNumber), _(bpAddress)));
+ } else if (reason == "breakpoint-hit") {
QByteArray bpNumber = data.findChild("bkptno").data();
QByteArray threadId = data.findChild("thread-id").data();
- showStatusMessage(tr("Stopped at breakpoint %1 in thread %2.")
+ showStatusMessage(tr("Stopped at breakpoint %1 in thread %2")
.arg(_(bpNumber), _(threadId)));
} else {
QString reasontr = tr("Stopped: \"%1\"").arg(_(reason));
// Ignore these as they are showing up regularly when
// stopping debugging.
if (name != STOP_SIGNAL
- && (startParameters().startMode != StartRemote
+ && (runControl()->sp().startMode != AttachToRemote
|| name != CROSS_STOP_SIGNAL)) {
QString msg = tr("<p>The inferior stopped because it received a "
"signal from the Operating System.<p>"
if (supportsThreads()) {
int currentId = data.findChild("thread-id").data().toInt();
- if (m_gdbAdapter->isTrkAdapter())
+ if (m_gdbAdapter->isTrkAdapter()) {
m_gdbAdapter->trkReloadThreads();
- else
- postCommand("-thread-list-ids", CB(handleStackListThreads), currentId);
+ } else if (m_isMacGdb) {
+ postCommand("-thread-list-ids", CB(handleThreadListIds), currentId);
+ } else {
+ // This is only available in gdb 7.1+.
+ postCommand("-thread-info", CB(handleThreadInfo), currentId);
+ }
}
//
manager()->reloadRegisters();
}
-#ifdef Q_OS_LINUX
void GdbEngine::handleInfoProc(const GdbResponse &response)
{
if (response.resultClass == GdbResultDone) {
maybeHandleInferiorPidChanged(re.cap(1));
}
}
-#endif
void GdbEngine::handleShowVersion(const GdbResponse &response)
{
- debugMessage(_("PARSING VERSION: " + response.toString()));
+ showMessage(_("PARSING VERSION: " + response.toString()));
if (response.resultClass == GdbResultDone) {
m_gdbVersion = 100;
m_gdbBuildVersion = -1;
extractGdbVersion(msg,
&m_gdbVersion, &m_gdbBuildVersion, &m_isMacGdb);
if (m_gdbVersion > 60500 && m_gdbVersion < 200000)
- debugMessage(_("SUPPORTED GDB VERSION ") + msg);
+ showMessage(_("SUPPORTED GDB VERSION ") + msg);
else
- debugMessage(_("UNSUPPORTED GDB VERSION ") + msg);
+ showMessage(_("UNSUPPORTED GDB VERSION ") + msg);
- debugMessage(_("USING GDB VERSION: %1, BUILD: %2%3").arg(m_gdbVersion)
+ showMessage(_("USING GDB VERSION: %1, BUILD: %2%3").arg(m_gdbVersion)
.arg(m_gdbBuildVersion).arg(_(m_isMacGdb ? " (APPLE)" : "")));
}
}
QByteArray cmd = "set environment ";
cmd += Debugger::Constants::Internal::LD_PRELOAD_ENV_VAR;
cmd += ' ';
- cmd += manager()->qtDumperLibraryName().toLocal8Bit();
+ cmd += runControl()->sp().startMode == StartRemoteGdb
+ ? runControl()->sp().remoteDumperLib
+ : cmd += manager()->qtDumperLibraryName().toLocal8Bit();
postCommand(cmd);
m_debuggingHelperState = DebuggingHelperLoadTried;
}
void GdbEngine::shutdown()
{
- debugMessage(_("INITIATE GDBENGINE SHUTDOWN"));
+ showMessage(_("INITIATE GDBENGINE SHUTDOWN"));
if (m_progress) {
m_progress->setProgressValue(90);
m_progress->reportCanceled();
m_gdbAdapter->shutdown();
// fall-through
case AdapterStartFailed: // Adapter "did something", but it did not help
- if (m_gdbProc.state() == QProcess::Running) {
+ if (gdbProc()->state() == QProcess::Running) {
m_commandsToRunOnTemporaryBreak.clear();
postCommand("-gdb-exit", GdbEngine::ExitRequest, CB(handleGdbExit));
} else {
// fall-through
case InferiorStopFailed: // Tough luck, I guess. But unreachable as of now anyway.
setState(EngineShuttingDown);
- m_gdbProc.kill();
+ gdbProc()->kill();
break;
}
}
{
QTC_ASSERT(state() == InferiorShuttingDown, qDebug() << state());
if (response.resultClass == GdbResultDone) {
- debugMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
+ showMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
setState(InferiorShutDown);
} else {
QByteArray ba = response.data.findChild("msg").data();
if (ba.contains(": No such file or directory.")) {
// This happens when someone removed the binary behind our back.
// It is not really an error from a user's point of view.
- debugMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
- debugMessage(_("NOTE: " + ba));
+ showMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
+ showMessage(_("NOTE: " + ba));
setState(InferiorShutDown);
} else {
- debugMessage(_("INFERIOR SHUTDOWN FAILED"));
+ showMessage(_("INFERIOR SHUTDOWN FAILED"));
setState(InferiorShutdownFailed);
showMessageBox(QMessageBox::Critical,
tr("Failed to shut down application"),
void GdbEngine::handleGdbExit(const GdbResponse &response)
{
if (response.resultClass == GdbResultExit) {
- debugMessage(_("GDB CLAIMS EXIT; WAITING"));
+ showMessage(_("GDB CLAIMS EXIT; WAITING"));
m_commandsDoneCallback = 0;
// Don't set state here, this will be handled in handleGdbFinished()
} else {
QString msg = m_gdbAdapter->msgGdbStopFailed(
QString::fromLocal8Bit(response.data.findChild("msg").data()));
- debugMessage(_("GDB WON'T EXIT (%1); KILLING IT").arg(msg));
- m_gdbProc.kill();
+ showMessage(_("GDB WON'T EXIT (%1); KILLING IT").arg(msg));
+ gdbProc()->kill();
}
}
{
disconnectDebuggingHelperActions();
shutdown();
- m_gdbProc.kill();
+ gdbProc()->kill();
}
int GdbEngine::currentFrame() const
return true;
}
-AbstractGdbAdapter *GdbEngine::createAdapter(const DebuggerStartParametersPtr &sp)
+AbstractGdbAdapter *GdbEngine::createAdapter()
{
- switch (sp->toolChainType) {
+ QTC_ASSERT(runControl(), return 0);
+ const DebuggerStartParameters &sp = runControl()->sp();
+ switch (sp.toolChainType) {
case ProjectExplorer::ToolChain::WINSCW: // S60
case ProjectExplorer::ToolChain::GCCE:
case ProjectExplorer::ToolChain::RVCT_ARMV5:
break;
}
// @todo: remove testing hack
- if (sp->processArgs.size() == 3 && sp->processArgs.at(0) == _("@sym@"))
+ if (sp.processArgs.size() == 3 && sp.processArgs.at(0) == _("@sym@"))
return new TrkGdbAdapter(this);
- switch (sp->startMode) {
+ switch (sp.startMode) {
case AttachCore:
return new CoreGdbAdapter(this);
- case StartRemote:
- return new RemoteGdbAdapter(this, sp->toolChainType);
+ case AttachToRemote:
+ return new RemoteGdbServerAdapter(this, sp.toolChainType);
+ case StartRemoteGdb:
+ return new RemotePlainGdbAdapter(this);
case AttachExternal:
return new AttachGdbAdapter(this);
default:
- if (sp->useTerminal)
+ if (sp.useTerminal)
return new TermGdbAdapter(this);
- return new PlainGdbAdapter(this);
+ return new LocalPlainGdbAdapter(this);
}
}
-void GdbEngine::startDebugger(const DebuggerStartParametersPtr &sp)
+void GdbEngine::startDebugger()
{
+ QTC_ASSERT(runControl(), return);
QTC_ASSERT(state() == EngineStarting, qDebug() << state());
// This should be set by the constructor or in exitDebugger()
// via initializeVariables()
fp->setKeepOnFinish(false);
m_progress->reportStarted();
- m_startParameters = sp;
-
delete m_gdbAdapter;
- m_gdbAdapter = createAdapter(sp);
+ m_gdbAdapter = createAdapter();
connectAdapter();
if (m_gdbAdapter->dumperHandling() != AbstractGdbAdapter::DumperNotAvailable)
| ReloadModuleSymbolsCapability | BreakOnThrowAndCatchCapability
| ReturnFromFunctionCapability
| CreateFullBacktraceCapability
+ | WatchpointCapability
| AddWatcherCapability;
}
);
}
PENDING_DEBUG("\n--- token barrier ---\n");
- showDebuggerInput(LogMisc, _("--- token barrier ---"));
+ showMessage(_("--- token barrier ---"), LogMiscInput);
if (theDebuggerBoolSetting(LogTimeStamps))
- showDebuggerInput(LogMisc, currentTime());
+ showMessage(currentTime(), LogMiscInput);
m_oldestAcceptableToken = currentToken();
}
//
//////////////////////////////////////////////////////////////////////
-void GdbEngine::breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt)
+void GdbEngine::setBreakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt)
{
if (!bkpt.isValid())
return;
if (ba.startsWith('<') && ba.endsWith('>'))
ba = ba.mid(1, ba.size() - 2);
data->bpFuncName = _(ba);
+ } else if (child.hasName("thread")) {
+ data->bpThreadSpec = child.data();
+ } else if (child.hasName("type")) {
+ if (child.data() == "breakpoint")
+ data->type = BreakpointData::BreakpointType;
+ else // FIXME: Incomplete list of cases.
+ data->type = BreakpointData::WatchpointType;
}
+ // This field is not present. Contents needs to be parsed from
+ // the plain "ignore" response.
+ //else if (child.hasName("ignore"))
+ // data->bpIgnoreCount = child.data();
}
- // This field is not present. Contents needs to be parsed from
- // the plain "ignore" response.
- //else if (child.hasName("ignore"))
- // data->bpIgnoreCount = child.data();
QString name;
if (!fullName.isEmpty()) {
return where;
}
-QByteArray GdbEngine::breakpointLocation(int index)
+QByteArray GdbEngine::breakpointLocation(const BreakpointData *data)
{
- const BreakpointData *data = manager()->breakHandler()->at(index);
if (!data->funcName.isEmpty())
return data->funcName.toLatin1();
// In this case, data->funcName is something like '*0xdeadbeef'
void GdbEngine::sendInsertBreakpoint(int index)
{
+ const BreakpointData *data = manager()->breakHandler()->at(index);
// Set up fallback in case of pending breakpoints which aren't handled
// by the MI interface.
+ if (data->type == BreakpointData::WatchpointType) {
+ postCommand("watch *" + data->address,
+ NeedsStop | RebuildBreakpointModel,
+ CB(handleWatchInsert), index);
+ return;
+ }
+
QByteArray cmd;
- if (m_isMacGdb)
+ if (m_isMacGdb) {
cmd = "-break-insert -l -1 -f ";
- else if (m_gdbAdapter->isTrkAdapter())
+ } else if (m_gdbAdapter->isTrkAdapter()) {
cmd = "-break-insert -h -f ";
- else if (m_gdbVersion >= 60800)
+ } else if (m_gdbVersion >= 70000) {
+ cmd = "-break-insert ";
+ if (!data->threadSpec.isEmpty())
+ cmd += "-p " + data->threadSpec;
+ cmd += " -f ";
+ } else if (m_gdbVersion >= 60800) {
// Probably some earlier version would work as well.
cmd = "-break-insert -f ";
- else
+ } else {
cmd = "-break-insert ";
+ }
//if (!data->condition.isEmpty())
// cmd += "-c " + data->condition + ' ';
- cmd += breakpointLocation(index);
+ cmd += breakpointLocation(data);
postCommand(cmd, NeedsStop | RebuildBreakpointModel,
CB(handleBreakInsert1), index);
}
+void GdbEngine::handleWatchInsert(const GdbResponse &response)
+{
+ int index = response.cookie.toInt();
+ if (response.resultClass == GdbResultDone) {
+ // "Hardware watchpoint 2: *0xbfffed40\n"
+ QByteArray ba = response.data.findChild("consolestreamoutput").data();
+ if (ba.startsWith("Hardware watchpoint ")) {
+ const int pos = ba.indexOf(':', 20);
+ BreakpointData *data = manager()->breakHandler()->at(index);
+ data->bpNumber = ba.mid(20, pos - 20);
+ manager()->breakHandler()->updateMarkers();
+ } else {
+ showMessage(_("CANNOT PARSE WATCHPOINT FROM" + ba));
+ }
+ }
+}
+
void GdbEngine::handleBreakInsert1(const GdbResponse &response)
{
int index = response.cookie.toInt();
- BreakHandler *handler = manager()->breakHandler();
+ BreakpointData *data = manager()->breakHandler()->at(index);
if (response.resultClass == GdbResultDone) {
// Interesting only on Mac?
- BreakpointData *data = handler->at(index);
GdbMi bkpt = response.data.findChild("bkpt");
- breakpointDataFromOutput(data, bkpt);
+ setBreakpointDataFromOutput(data, bkpt);
} else {
// Some versions of gdb like "GNU gdb (GDB) SUSE (6.8.91.20090930-2.4)"
// know how to do pending breakpoints using CLI but not MI. So try
// again with MI.
- QByteArray cmd = "break " + breakpointLocation(index);
+ QByteArray cmd = "break " + breakpointLocation(data);
postCommand(cmd, NeedsStop | RebuildBreakpointModel,
CB(handleBreakInsert2), index);
}
void GdbEngine::handleBreakList(const GdbMi &table)
{
- GdbMi body = table.findChild("body");
+ const GdbMi body = table.findChild("body");
QList<GdbMi> bkpts;
if (body.isValid()) {
// Non-Mac
}
BreakHandler *handler = manager()->breakHandler();
- for (int index = 0; index != bkpts.size(); ++index) {
- BreakpointData temp(handler);
- breakpointDataFromOutput(&temp, bkpts.at(index));
- int found = handler->findBreakpoint(temp);
- if (found != -1)
- breakpointDataFromOutput(handler->at(found), bkpts.at(index));
- //else
- //qDebug() << "CANNOT HANDLE RESPONSE" << bkpts.at(index).toString();
+ foreach (const GdbMi &bkpt, bkpts) {
+ BreakpointData temp;
+ setBreakpointDataFromOutput(&temp, bkpt);
+ BreakpointData *data = handler->findSimilarBreakpoint(temp);
+ //qDebug() << "\n\nGOT: " << bkpt.toString() << '\n' << temp.toString();
+ if (data) {
+ //qDebug() << " FROM: " << data->toString();
+ setBreakpointDataFromOutput(data, bkpt);
+ //qDebug() << " TO: " << data->toString();
+ } else {
+ //qDebug() << " NOTHING SUITABLE FOUND";
+ showMessage(_("CANNOT FIND BP: " + bkpt.toString()));
+ }
}
m_breakListOutdated = false;
//
// gdb 6.3 does not produce any console output
BreakHandler *handler = manager()->breakHandler();
- BreakpointData *data = handler->findBreakpoint(bpNumber);
+ BreakpointData *data = handler->findBreakpointByNumber(bpNumber);
if (response.resultClass == GdbResultDone && data) {
QString msg = _(response.data.findChild("consolestreamoutput").data());
//if (msg.contains(__("Will stop next time breakpoint"))) {
{
int bpNumber = response.cookie.toInt();
BreakHandler *handler = manager()->breakHandler();
- BreakpointData *data = handler->findBreakpoint(bpNumber);
+ BreakpointData *data = handler->findBreakpointByNumber(bpNumber);
if (response.resultClass == GdbResultDone) {
// We just assume it was successful. Otherwise we had to parse
// the output stream data.
// constructor.
const int bpNumber = response.cookie.toInt();
const BreakHandler *handler = manager()->breakHandler();
- BreakpointData *data = handler->findBreakpoint(bpNumber);
+ BreakpointData *data = handler->findBreakpointByNumber(bpNumber);
if (data) {
QString str = QString::fromLocal8Bit(
response.data.findChild("consolestreamoutput").data());
// <_Z10testQStackv+142>.\n"
const int bpNumber = response.cookie.toInt();
const BreakHandler *handler = manager()->breakHandler();
- BreakpointData *data = handler->findBreakpoint(bpNumber);
+ BreakpointData *data = handler->findBreakpointByNumber(bpNumber);
if (!data)
return;
QByteArray ba = response.data.findChild("consolestreamoutput").data();
{
QTC_ASSERT(!m_sourcesListUpdating,
qDebug() << "SOURCES LIST CURRENTLY UPDATING"; return);
- debugMessage(tr("ATTEMPT BREAKPOINT SYNC"));
+ showMessage(_("ATTEMPT BREAKPOINT SYNC"));
switch (state()) {
case InferiorStarting:
break;
default:
//qDebug() << "attempted breakpoint sync in state" << state();
+ showMessage(_("... NOT POSSIBLE IN CURRENT STATE"));
return;
}
foreach (BreakpointData *data, handler->takeRemovedBreakpoints()) {
QByteArray bpNumber = data->bpNumber;
- debugMessage(_("DELETING BP " + bpNumber + " IN "
- + data->markerFileName().toLocal8Bit()));
- if (!bpNumber.trimmed().isEmpty())
+ if (!bpNumber.trimmed().isEmpty()) {
+ showMessage(_("DELETING BP " + bpNumber + " IN "
+ + data->markerFileName().toLocal8Bit()));
postCommand("-break-delete " + bpNumber,
NeedsStop | RebuildBreakpointModel);
+ } else {
+ showMessage(_("QUIETLY REMOVING UNNUMBERED BREAKPOINT"));
+ }
delete data;
}
else // Because gdb won't do both changes at a time anyway.
if (data->ignoreCount != data->bpIgnoreCount) {
// Update ignorecount if needed.
- postCommand("ignore " + data->bpNumber + ' ' + data->ignoreCount,
+ QByteArray ic = QByteArray::number(data->ignoreCount.toInt());
+ postCommand("ignore " + data->bpNumber + ' ' + ic,
NeedsStop | RebuildBreakpointModel,
CB(handleBreakIgnore), data->bpNumber.toInt());
continue;
if (!data->enabled && data->bpEnabled) {
postCommand("-break-disable " + data->bpNumber,
NeedsStop | RebuildBreakpointModel,
- CB(handleBreakInfo));
+ CB(handleBreakDisable), data->bpNumber.toInt());
data->bpEnabled = false;
continue;
}
+ if (data->threadSpec != data->bpThreadSpec && !data->bpNumber.isEmpty()) {
+ // The only way to change this seems to be to re-set the bp completely.
+ //qDebug() << "FIXME: THREAD: " << data->threadSpec << data->bpThreadSpec;
+ data->bpThreadSpec.clear();
+ postCommand("-break-delete " + data->bpNumber,
+ NeedsStop | RebuildBreakpointModel);
+ sendInsertBreakpoint(index);
+ continue;
+ }
if (data->bpAddress.startsWith("0x")
&& data->bpCorrectedLineNumber.isEmpty()) {
// Prevent endless loop.
reloadModulesInternal();
}
-QList<Symbol> GdbEngine::moduleSymbols(const QString &moduleName)
+void GdbEngine::requestModuleSymbols(const QString &moduleName)
{
QList<Symbol> rc;
bool success = false;
} while (false);
if (!success)
qWarning("moduleSymbols: %s\n", qPrintable(errorMessage));
- return rc;
+ manager()->showModuleSymbols(moduleName, rc);
}
void GdbEngine::reloadModules()
stackFrames.append(parseStackFrame(stack.childAt(i), i));
const StackFrame &frame = stackFrames.back();
- #if defined(Q_OS_WIN)
+# if defined(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
showStatusMessage(tr("Jumping out of bogus frame..."), 1000);
return;
}
- #endif
+# endif
// Initialize top frame to the first valid frame.
const bool isValid = frame.isUsable() && !frame.function.isEmpty();
reloadRegisters();
}
-void GdbEngine::handleStackListThreads(const GdbResponse &response)
+void GdbEngine::handleThreadInfo(const GdbResponse &response)
+{
+ int id = response.cookie.toInt();
+ if (response.resultClass == GdbResultDone) {
+ // ^done,threads=[{id="1",target-id="Thread 0xb7fdc710 (LWP 4264)",
+ // frame={level="0",addr="0x080530bf",func="testQString",args=[],
+ // file="/.../app.cpp",fullname="/../app.cpp",line="1175"},
+ // state="stopped",core="0"}],current-thread-id="1"
+ const QList<GdbMi> items = response.data.findChild("threads").children();
+ QList<ThreadData> threads;
+ for (int index = 0, n = items.size(); index != n; ++index) {
+ bool ok = false;
+ const GdbMi item = items.at(index);
+ const GdbMi frame = item.findChild("frame");
+ ThreadData thread;
+ thread.id = item.findChild("id").data().toInt();
+ thread.targetId = item.findChild("target-id").data().toInt();
+ thread.core = QString::fromLatin1(item.findChild("core").data());
+ thread.state = QString::fromLatin1(item.findChild("state").data());
+ thread.address = frame.findChild("addr").data().toULongLong(&ok, 0);
+ thread.function = QString::fromLatin1(frame.findChild("func").data());
+ thread.fileName = QString::fromLatin1(frame.findChild("fullname").data());
+ thread.lineNumber = frame.findChild("line").data().toInt();
+ threads.append(thread);
+ }
+ ThreadsHandler *threadsHandler = manager()->threadsHandler();
+ threadsHandler->setThreads(threads);
+ int currentIndex = response.data.findChild("current-thread-id").data().toInt();
+ threadsHandler->setCurrentThread(currentIndex);
+ } else {
+ // Fall back for older versions: Try to get at least a list
+ // of running threads.
+ postCommand("-thread-list-ids", CB(handleThreadListIds), id);
+ }
+}
+
+void GdbEngine::handleThreadListIds(const GdbResponse &response)
{
int id = response.cookie.toInt();
// "72^done,{thread-ids={thread-id="2",thread-id="1"},number-of-threads="2"}
+ // In gdb 7.1+ additionally: current-thread-id="1"
const QList<GdbMi> items = response.data.findChild("thread-ids").children();
QList<ThreadData> threads;
int currentIndex = -1;
void GdbEngine::activateSnapshot(int index)
{
+ QTC_ASSERT(runControl(), return);
SnapshotData snapshot = m_manager->snapshotHandler()->setCurrentIndex(index);
- m_startParameters->startMode = AttachCore;
- m_startParameters->coreFile = snapshot.location();
+
+ DebuggerStartParameters &sp = const_cast<DebuggerStartParameters &>(runControl()->sp());
+ sp.startMode = AttachCore;
+ sp.coreFile = snapshot.location();
if (state() == InferiorUnrunnable) {
// All is well. We are looking at another core file.
"snapshot?"), QMessageBox::Ok | QMessageBox::Cancel);
if (mb->exec() == QMessageBox::Cancel)
return;
- debugMessage(_("KILLING DEBUGGER AS REQUESTED BY USER"));
+ showMessage(_("KILLING DEBUGGER AS REQUESTED BY USER"));
delete m_gdbAdapter;
- m_gdbAdapter = createAdapter(m_startParameters);
+ m_gdbAdapter = createAdapter();
postCommand("kill", NeedsStop, CB(handleActivateSnapshot));
} else {
activateSnapshot2();
//qDebug() << "PROCESSED NAMES: " << processedName << m_processedNames;
if (m_processedNames.contains(processedName)) {
WatchData data1 = data;
- showDebuggerInput(LogStatus,
- _("<Breaking endless loop for " + data.iname + '>'));
+ showMessage(_("<Breaking endless loop for " + data.iname + '>'),
+ LogMiscInput);
data1.setAllUnneeded();
data1.setValue(_("<unavailable>"));
data1.setHasChildren(false);
{
//m_pendingRequests = 0;
PENDING_DEBUG("UPDATE WATCH DATA");
- #if DEBUG_PENDING
+# if DEBUG_PENDING
//qDebug() << "##############################################";
qDebug() << "UPDATE MODEL, FOUND INCOMPLETE:";
//qDebug() << data.toString();
- #endif
+# endif
updateSubItemClassic(data);
//PENDING_DEBUG("INTERNAL TRIGGERING UPDATE WATCH MODEL");
m_processedNames.clear();
PENDING_DEBUG("REBUILDING MODEL" << count);
if (theDebuggerBoolSetting(LogTimeStamps))
- showDebuggerInput(LogMisc, currentTime());
- showDebuggerInput(LogStatus, _("<Rebuild Watchmodel %1>").arg(count));
+ showMessage(currentTime(), LogMiscInput);
+ showMessage(_("<Rebuild Watchmodel %1>").arg(count), LogMiscInput);
showStatusMessage(tr("Finished retrieving data"), 400);
manager()->watchHandler()->endCycle();
showToolTip();
static QByteArray arrayFillCommand(const char *array, const QByteArray ¶ms)
{
- char buf[50];
- sprintf(buf, "set {char[%d]} &%s = {", params.size(), array);
+ QString buf;
+ buf.sprintf("set {char[%d]} &%s = {", params.size(), array);
QByteArray encoded;
- encoded.append(buf);
+ encoded.append(buf.toLocal8Bit());
const int size = params.size();
for (int i = 0; i != size; ++i) {
- sprintf(buf, "%d,", int(params[i]));
- encoded.append(buf);
+ buf.sprintf("%d,", int(params[i]));
+ encoded.append(buf.toLocal8Bit());
}
encoded[encoded.size() - 1] = '}';
return encoded;
const QByteArray inBufferCmd = arrayFillCommand("qDumpInBuffer", params);
params.replace('\0','!');
- showDebuggerInput(LogMisc, QString::fromUtf8(params));
+ showMessage(QString::fromUtf8(params), LogMiscInput);
params.clear();
params.append('\0');
if (ac.agent->contentsCoversAddress(contents)) {
ac.agent->setContents(parseDisassembler(lines));
} else {
- debugMessage(_("FALL BACK TO NON-MIXED"));
+ showMessage(_("FALL BACK TO NON-MIXED"));
fetchDisassemblerByAddress(ac, false);
}
}
bool GdbEngine::startGdb(const QStringList &args, const QString &gdb, const QString &settingsIdHint)
{
- m_gdbProc.disconnect(); // From any previous runs
+ gdbProc()->disconnect(); // From any previous runs
m_gdb = QString::fromLatin1(qgetenv("QTC_DEBUGGER_PATH"));
if (m_gdb.isEmpty())
- m_gdb = m_gdbBinaryToolChainMap->key(m_startParameters->toolChainType);
+ m_gdb = m_gdbBinaryToolChainMap->key(m_runControl->sp().toolChainType);
if (m_gdb.isEmpty())
m_gdb = gdb;
if (m_gdb.isEmpty()) {
- handleAdapterStartFailed(msgNoBinaryForToolChain(m_startParameters->toolChainType),
+ handleAdapterStartFailed(msgNoBinaryForToolChain(m_runControl->sp().toolChainType),
GdbOptionsPage::settingsId());
return false;
}
- debugMessage(_("STARTING GDB ") + m_gdb);
+ showMessage(_("STARTING GDB ") + m_gdb);
QStringList gdbArgs;
gdbArgs << _("-i");
gdbArgs << _("mi");
const QString winPythonVersion = QLatin1String(winPythonVersionC);
const QDir dir = fi.absoluteDir();
if (dir.exists(winPythonVersion)) {
- QProcessEnvironment environment = m_gdbProc.processEnvironment();
+ QProcessEnvironment environment = gdbProc()->processEnvironment();
const QString pythonPathVariable = QLatin1String("PYTHONPATH");
// Check for existing values.
if (environment.contains(pythonPathVariable)) {
const QString oldPythonPath = environment.value(pythonPathVariable);
- manager()->showDebuggerOutput(LogMisc,
- _("Using existing python path: %1").arg(oldPythonPath));
+ showMessage(_("Using existing python path: %1")
+ .arg(oldPythonPath), LogMisc);
} else {
const QString pythonPath =
QDir::toNativeSeparators(dir.absoluteFilePath(winPythonVersion));
environment.insert(pythonPathVariable, pythonPath);
- manager()->showDebuggerOutput(LogMisc,
- _("Python path: %1").arg(pythonPath));
- m_gdbProc.setProcessEnvironment(environment);
+ showMessage(_("Python path: %1").arg(pythonPath), LogMisc);
+ gdbProc()->setProcessEnvironment(environment);
}
foundPython = true;
}
}
if (!foundPython) {
- debugMessage(_("UNSUPPORTED GDB %1 DOES NOT HAVE PYTHON.").arg(m_gdb));
- showStatusMessage(_("Gdb at %1 does not have python.").arg(m_gdb));
+ showMessage(_("UNSUPPORTED GDB %1 DOES NOT HAVE PYTHON.").arg(m_gdb));
+ showStatusMessage(_("Gdb at %1 does not have python").arg(m_gdb));
}
#endif
- connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)),
+ connect(gdbProc(), SIGNAL(error(QProcess::ProcessError)),
SLOT(handleGdbError(QProcess::ProcessError)));
- connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)),
+ connect(gdbProc(), SIGNAL(finished(int, QProcess::ExitStatus)),
SLOT(handleGdbFinished(int, QProcess::ExitStatus)));
- connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()),
+ connect(gdbProc(), SIGNAL(readyReadStandardOutput()),
SLOT(readGdbStandardOutput()));
- connect(&m_gdbProc, SIGNAL(readyReadStandardError()),
+ connect(gdbProc(), SIGNAL(readyReadStandardError()),
SLOT(readGdbStandardError()));
- m_gdbProc.start(m_gdb, gdbArgs);
+ gdbProc()->start(m_gdb, gdbArgs);
- if (!m_gdbProc.waitForStarted()) {
+ if (!gdbProc()->waitForStarted()) {
const QString msg = tr("Unable to start gdb '%1': %2")
- .arg(m_gdb, m_gdbProc.errorString());
+ .arg(m_gdb, gdbProc()->errorString());
handleAdapterStartFailed(msg, settingsIdHint);
return false;
}
const QByteArray dumperSourcePath =
Core::ICore::instance()->resourcePath().toLocal8Bit() + "/gdbmacros/";
- debugMessage(_("GDB STARTED, INITIALIZING IT"));
+ showMessage(_("GDB STARTED, INITIALIZING IT"));
m_commandTimer->setInterval(commandTimeoutTime());
postCommand("show version", CB(handleShowVersion));
void GdbEngine::handleGdbError(QProcess::ProcessError error)
{
- debugMessage(_("HANDLE GDB ERROR"));
+ showMessage(_("HANDLE GDB ERROR"));
switch (error) {
case QProcess::Crashed:
break; // will get a processExited() as well
case QProcess::WriteError:
case QProcess::Timedout:
default:
- m_gdbProc.kill();
+ gdbProc()->kill();
setState(EngineShuttingDown, true);
showMessageBox(QMessageBox::Critical, tr("Gdb I/O Error"),
errorMessage(error));
void GdbEngine::handleGdbFinished(int code, QProcess::ExitStatus type)
{
- debugMessage(_("GDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
+ showMessage(_("GDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
if (!m_gdbAdapter) {
- debugMessage(_("NO ADAPTER PRESENT"));
+ showMessage(_("NO ADAPTER PRESENT"));
} else if (state() == EngineShuttingDown) {
- debugMessage(_("GOING TO SHUT DOWN ADAPTER"));
+ showMessage(_("GOING TO SHUT DOWN ADAPTER"));
m_gdbAdapter->shutdown();
} else if (state() != AdapterStartFailed) {
QString msg = tr("The gdb process exited unexpectedly (%1).")
void GdbEngine::handleAdapterStartFailed(const QString &msg, const QString &settingsIdHint)
{
setState(AdapterStartFailed);
- debugMessage(_("ADAPTER START FAILED"));
+ showMessage(_("ADAPTER START FAILED"));
if (!msg.isEmpty()) {
const QString title = tr("Adapter start failed");
if (settingsIdHint.isEmpty()) {
setState(AdapterStarted);
if (m_progress)
m_progress->setProgressValue(25);
- debugMessage(_("ADAPTER SUCCESSFULLY STARTED"));
+ showMessage(_("ADAPTER SUCCESSFULLY STARTED"));
showStatusMessage(tr("Starting inferior..."));
setState(InferiorStarting);
void GdbEngine::handleInferiorPrepared()
{
- const QByteArray qtInstallPath = m_startParameters->qtInstallPath.toLocal8Bit();
+ const QByteArray qtInstallPath = m_runControl->sp().qtInstallPath.toLocal8Bit();
if (!qtInstallPath.isEmpty()) {
QByteArray qtBuildPath;
#if defined(Q_OS_WIN)
// Initial attempt to set breakpoints
showStatusMessage(tr("Setting breakpoints..."));
- debugMessage(tr("Setting breakpoints..."));
+ showMessage(tr("Setting breakpoints..."));
attemptBreakpointSynchronization();
if (m_cookieForToken.isEmpty()) {
void GdbEngine::startInferiorPhase2()
{
- debugMessage(_("BREAKPOINTS SET, CONTINUING INFERIOR STARTUP"));
+ showMessage(_("BREAKPOINTS SET, CONTINUING INFERIOR STARTUP"));
m_gdbAdapter->startInferiorPhase2();
}
{
showStatusMessage(tr("Failed to start application: ") + msg);
if (state() == AdapterStartFailed) {
- debugMessage(_("INFERIOR START FAILED, BUT ADAPTER DIED ALREADY"));
+ showMessage(_("INFERIOR START FAILED, BUT ADAPTER DIED ALREADY"));
return; // Adapter crashed meanwhile, so this notification is meaningless.
}
- debugMessage(_("INFERIOR START FAILED"));
+ showMessage(_("INFERIOR START FAILED"));
showMessageBox(QMessageBox::Critical, tr("Failed to start application"), msg);
setState(InferiorStartFailed);
shutdown();
void GdbEngine::handleAdapterCrashed(const QString &msg)
{
- debugMessage(_("ADAPTER CRASHED"));
+ showMessage(_("ADAPTER CRASHED"));
// The adapter is expected to have cleaned up after itself when we get here,
// so the effect is about the same as AdapterStartFailed => use it.
setState(AdapterStartFailed, true);
// No point in being friendly here ...
- m_gdbProc.kill();
+ gdbProc()->kill();
if (!msg.isEmpty())
showMessageBox(QMessageBox::Critical, tr("Adapter crashed"), msg);
#include "idebuggerengine.h"
#include "debuggermanager.h" // only for StartParameters
#include "gdbmi.h"
+#include "localgdbprocess.h"
#include "watchutils.h"
#include <QtCore/QByteArray>
#include <QtCore/QMap>
#include <QtCore/QMultiMap>
#include <QtCore/QObject>
-#include <QtCore/QProcess>
#include <QtCore/QPoint>
#include <QtCore/QSet>
#include <QtCore/QTextCodec>
namespace Internal {
class AbstractGdbAdapter;
+class AbstractGdbProcess;
class GdbResponse;
class GdbMi;
class AttachGdbAdapter;
class CoreGdbAdapter;
-class PlainGdbAdapter;
-class RemoteGdbAdapter;
+class LocalPlainGdbAdapter;
+class RemoteGdbServerAdapter;
class TrkGdbAdapter;
enum DebuggingHelperState
private:
friend class AbstractGdbAdapter;
+ friend class AbstractPlainGdbAdapter;
friend class AttachGdbAdapter;
friend class CoreGdbAdapter;
- friend class PlainGdbAdapter;
+ friend class LocalPlainGdbAdapter;
friend class TermGdbAdapter;
- friend class RemoteGdbAdapter;
+ friend class RemoteGdbServerAdapter;
+ friend class RemotePlainGdbAdapter;
friend class TrkGdbAdapter;
private: ////////// General Interface //////////
virtual bool checkConfiguration(int toolChain, QString *errorMessage,
QString *settingsPage = 0) const;
- virtual void startDebugger(const DebuggerStartParametersPtr &sp);
+ virtual void startDebugger();
virtual unsigned debuggerCapabilities() const;
virtual void exitDebugger();
virtual void abortDebugger();
void initializeVariables();
DebuggerStartMode startMode() const;
const DebuggerStartParameters &startParameters() const
- { return *m_startParameters; }
+ { return m_runControl->sp(); }
Q_SLOT void setAutoDerefPointers(const QVariant &on);
- DebuggerStartParametersPtr m_startParameters;
bool m_registerNamesListed;
private: ////////// Gdb Process Management //////////
- AbstractGdbAdapter *createAdapter(const DebuggerStartParametersPtr &dp);
+ AbstractGdbAdapter *createAdapter();
void connectAdapter();
bool startGdb(const QStringList &args = QStringList(),
const QString &gdb = QString(),
QByteArray m_inbuffer;
bool m_busy;
- QProcess m_gdbProc;
AbstractGdbAdapter *m_gdbAdapter;
+ // Name of the convenience variable containing the last
+ // known function return value.
+ QByteArray m_resultVarName;
+
private: ////////// Gdb Command Management //////////
public: // Otherwise the Qt flag macros are unhappy.
qint64 inferiorPid() const { return m_manager->inferiorPid(); }
void handleInferiorPidChanged(qint64 pid) { manager()->notifyInferiorPidChanged(pid); }
void maybeHandleInferiorPidChanged(const QString &pid);
-
-#ifdef Q_OS_LINUX
void handleInfoProc(const GdbResponse &response);
QByteArray m_entryPoint;
-#endif
QFutureInterface<void> *m_progress;
private: ////////// View & Data Stuff //////////
void handleBreakInsert2(const GdbResponse &response);
void handleBreakCondition(const GdbResponse &response);
void handleBreakInfo(const GdbResponse &response);
+ void handleWatchInsert(const GdbResponse &response);
void handleInfoLine(const GdbResponse &response);
void extractDataFromInfoBreak(const QString &output, BreakpointData *data);
- void breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt);
- QByteArray breakpointLocation(int index);
+ void setBreakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt);
+ QByteArray breakpointLocation(const BreakpointData *data);
void sendInsertBreakpoint(int index);
QString breakLocation(const QString &file) const;
void reloadBreakListInternal();
//
virtual void loadSymbols(const QString &moduleName);
virtual void loadAllSymbols();
- virtual QList<Symbol> moduleSymbols(const QString &moduleName);
+ virtual void requestModuleSymbols(const QString &moduleName);
virtual void reloadModules();
void reloadModulesInternal();
void handleModulesList(const GdbResponse &response);
void handleStackListFrames(const GdbResponse &response);
void handleStackSelectThread(const GdbResponse &response);
void handleStackSelectFrame(const GdbResponse &response);
- void handleStackListThreads(const GdbResponse &response);
+ void handleThreadListIds(const GdbResponse &response);
+ void handleThreadInfo(const GdbResponse &response);
Q_SLOT void reloadStack(bool forceGotoLocation);
Q_SLOT virtual void reloadFullStack();
int currentFrame() const;
void handleDebuggingHelperValue3Classic(const GdbResponse &response);
void handleDebuggingHelperEditValue(const GdbResponse &response);
void handleDebuggingHelperSetup(const GdbResponse &response);
+ void handleDebuggingHelperVersionCheckClassic(const GdbResponse &response);
Q_SLOT void createFullBacktrace();
void handleCreateFullBacktrace(const GdbResponse &response);
QString errorMessage(QProcess::ProcessError error);
QMessageBox *showMessageBox(int icon, const QString &title, const QString &text,
int buttons = 0);
- void debugMessage(const QString &msg);
QMainWindow *mainWindow() const;
+ AbstractGdbProcess *gdbProc() const;
static QString m_toolTipExpression;
static QPoint m_toolTipPos;
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "localgdbprocess.h"
+
+namespace Debugger {
+namespace Internal {
+
+LocalGdbProcess::LocalGdbProcess(QObject *parent) : AbstractGdbProcess(parent)
+{
+ connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)),
+ this, SIGNAL(error(QProcess::ProcessError)));
+ connect(&m_gdbProc, SIGNAL(finished(int,QProcess::ExitStatus)),
+ this, SIGNAL(finished(int,QProcess::ExitStatus)));
+ connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()),
+ this, SIGNAL(readyReadStandardOutput()));
+ connect(&m_gdbProc, SIGNAL(readyReadStandardError()),
+ this, SIGNAL(readyReadStandardError()));
+}
+
+QByteArray LocalGdbProcess::readAllStandardOutput()
+{
+ return m_gdbProc.readAllStandardOutput();
+}
+
+QByteArray LocalGdbProcess::readAllStandardError()
+{
+ return m_gdbProc.readAllStandardError();
+}
+
+void LocalGdbProcess::start(const QString &cmd, const QStringList &args)
+{
+ m_gdbProc.start(cmd, args);
+}
+
+bool LocalGdbProcess::waitForStarted()
+{
+ return m_gdbProc.waitForStarted();
+}
+
+qint64 LocalGdbProcess::write(const QByteArray &data)
+{
+ return m_gdbProc.write(data);
+}
+
+void LocalGdbProcess::kill()
+{
+ m_gdbProc.kill();
+}
+
+QProcess::ProcessState LocalGdbProcess::state() const
+{
+ return m_gdbProc.state();
+}
+
+QString LocalGdbProcess::errorString() const
+{
+ return m_gdbProc.errorString();
+}
+
+QProcessEnvironment LocalGdbProcess::processEnvironment() const
+{
+ return m_gdbProc.processEnvironment();
+}
+
+void LocalGdbProcess::setProcessEnvironment(const QProcessEnvironment &env)
+{
+ m_gdbProc.setProcessEnvironment(env);
+}
+
+void LocalGdbProcess::setEnvironment(const QStringList &env)
+{
+ m_gdbProc.setEnvironment(env);
+}
+
+void LocalGdbProcess::setWorkingDirectory(const QString &dir)
+{
+ m_gdbProc.setWorkingDirectory(dir);
+}
+
+} // namespace Internal
+} // namespace Debugger
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef LOCALGDBPROCESS_H
+#define LOCALGDBPROCESS_H
+
+#include "abstractgdbprocess.h"
+
+namespace Debugger {
+namespace Internal {
+
+class LocalGdbProcess : public AbstractGdbProcess
+{
+public:
+ explicit LocalGdbProcess(QObject *parent = 0);
+
+ virtual QByteArray readAllStandardOutput();
+ virtual QByteArray readAllStandardError();
+
+ virtual void start(const QString &cmd, const QStringList &args);
+ virtual bool waitForStarted();
+ virtual qint64 write(const QByteArray &data);
+ virtual void kill();
+
+ virtual QProcess::ProcessState state() const;
+ virtual QString errorString() const;
+
+ virtual QProcessEnvironment processEnvironment() const;
+ virtual void setProcessEnvironment(const QProcessEnvironment &env);
+ virtual void setEnvironment(const QStringList &env);
+ virtual void setWorkingDirectory(const QString &dir);
+
+private:
+ QProcess m_gdbProc;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // LOCALGDBPROCESS_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "localplaingdbadapter.h"
+
+#include "gdbengine.h"
+#include "procinterrupt.h"
+#include "debuggerstringutils.h"
+
+#include <utils/qtcassert.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QProcess>
+#include <QtGui/QMessageBox>
+
+namespace Debugger {
+namespace Internal {
+
+///////////////////////////////////////////////////////////////////////
+//
+// PlainGdbAdapter
+//
+///////////////////////////////////////////////////////////////////////
+
+LocalPlainGdbAdapter::LocalPlainGdbAdapter(GdbEngine *engine, QObject *parent)
+ : AbstractPlainGdbAdapter(engine, parent)
+{
+ // Output
+ connect(&m_outputCollector, SIGNAL(byteDelivery(QByteArray)),
+ engine, SLOT(readDebugeeOutput(QByteArray)));
+}
+
+AbstractGdbAdapter::DumperHandling LocalPlainGdbAdapter::dumperHandling() const
+{
+ // LD_PRELOAD fails for System-Qt on Mac.
+#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
+ return DumperLoadedByGdb;
+#else
+ return DumperLoadedByGdbPreload;
+#endif
+}
+
+void LocalPlainGdbAdapter::startAdapter()
+{
+ QTC_ASSERT(state() == EngineStarting, qDebug() << state());
+ setState(AdapterStarting);
+ showMessage(_("TRYING TO START ADAPTER"));
+
+ QStringList gdbArgs;
+
+ if (!m_outputCollector.listen()) {
+ emit adapterStartFailed(tr("Cannot set up communication with child process: %1")
+ .arg(m_outputCollector.errorString()), QString());
+ return;
+ }
+ gdbArgs.append(_("--tty=") + m_outputCollector.serverName());
+
+ if (!startParameters().workingDirectory.isEmpty())
+ m_gdbProc.setWorkingDirectory(startParameters().workingDirectory);
+ if (!startParameters().environment.isEmpty())
+ m_gdbProc.setEnvironment(startParameters().environment);
+
+ if (!m_engine->startGdb(gdbArgs)) {
+ m_outputCollector.shutdown();
+ return;
+ }
+
+ emit adapterStarted();
+ checkForReleaseBuild();
+}
+
+void LocalPlainGdbAdapter::checkForReleaseBuild()
+{
+ // Quick check for a "release" build
+ QProcess proc;
+ QStringList args;
+ args.append(_("-h"));
+ args.append(_("-j"));
+ args.append(_(".debug_info"));
+ args.append(startParameters().executable);
+ proc.start(_("objdump"), args);
+ proc.closeWriteChannel();
+ QTC_ASSERT(proc.waitForStarted(), qDebug() << "UNABLE TO RUN OBJDUMP");
+ proc.waitForFinished();
+ QByteArray ba = proc.readAllStandardOutput();
+ // This should yield something like
+ // "debuggertest: file format elf32-i386\n\n"
+ // "Sections:\nIdx Name Size VMA LMA File off Algn\n"
+ // "30 .debug_info 00087d36 00000000 00000000 0006bbd5 2**0\n"
+ // " CONTENTS, READONLY, DEBUGGING"
+ if (ba.contains("Sections:") && !ba.contains(".debug_info")) {
+ m_engine->showMessageBox(QMessageBox::Information, "Warning",
+ tr("This does not seem to be a \"Debug\" build.\n"
+ "Setting breakpoints by file name and line number may fail."));
+ }
+}
+
+void LocalPlainGdbAdapter::interruptInferior()
+{
+ const qint64 attachedPID = m_engine->inferiorPid();
+ if (attachedPID <= 0) {
+ showMessage(_("TRYING TO INTERRUPT INFERIOR BEFORE PID WAS OBTAINED"));
+ return;
+ }
+
+ if (!interruptProcess(attachedPID))
+ showMessage(_("CANNOT INTERRUPT %1").arg(attachedPID));
+}
+
+void LocalPlainGdbAdapter::shutdown()
+{
+ showMessage(_("PLAIN ADAPTER SHUTDOWN %1").arg(state()));
+ m_outputCollector.shutdown();
+}
+
+QByteArray LocalPlainGdbAdapter::execFilePath() const
+{
+ return QFileInfo(startParameters().executable)
+ .absoluteFilePath().toLocal8Bit();
+}
+
+bool LocalPlainGdbAdapter::infoTargetNecessary() const
+{
+#ifdef Q_OS_LINUX
+ return true;
+#else
+ return false;
+#endif
+}
+
+QByteArray LocalPlainGdbAdapter::toLocalEncoding(const QString &s) const
+{
+ return s.toLocal8Bit();
+}
+
+QString LocalPlainGdbAdapter::fromLocalEncoding(const QByteArray &b) const
+{
+ return QString::fromLocal8Bit(b);
+}
+
+} // namespace Internal
+} // namespace Debugger
#ifndef DEBUGGER_PLAINGDBADAPTER_H
#define DEBUGGER_PLAINGDBADAPTER_H
-#include "abstractgdbadapter.h"
+#include "abstractplaingdbadapter.h"
+
+#include "abstractgdbprocess.h"
#include <outputcollector.h>
//
///////////////////////////////////////////////////////////////////////
-class PlainGdbAdapter : public AbstractGdbAdapter
+class LocalPlainGdbAdapter : public AbstractPlainGdbAdapter
{
Q_OBJECT
public:
- PlainGdbAdapter(GdbEngine *engine, QObject *parent = 0);
+ LocalPlainGdbAdapter(GdbEngine *engine, QObject *parent = 0);
virtual DumperHandling dumperHandling() const;
void startAdapter();
- void startInferior();
- void startInferiorPhase2();
void interruptInferior();
void shutdown();
- const char *inferiorShutdownCommand() const { return "kill"; }
+ AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
private:
- void handleFileExecAndSymbols(const GdbResponse &response);
- void handleExecRun(const GdbResponse &response);
-#ifdef Q_OS_LINUX
- void handleInfoTarget(const GdbResponse &response);
-#endif
+ virtual QByteArray execFilePath() const;
+ virtual bool infoTargetNecessary() const;
+ virtual QByteArray toLocalEncoding(const QString &s) const;
+ virtual QString fromLocalEncoding(const QByteArray &b) const;
+ void checkForReleaseBuild();
OutputCollector m_outputCollector;
+ LocalGdbProcess m_gdbProc;
};
} // namespace Internal
options += "defaults,";
options.chop(1);
+ QByteArray resultVar;
+ if (!m_resultVarName.isEmpty())
+ resultVar = "resultvarname:" + m_resultVarName + ' ';
+
postCommand("bb options:" + options + " vars:" + varList + ' '
- + expanded + " watchers:" + watchers.toHex(),
+ + resultVar + expanded + " watchers:" + watchers.toHex(),
WatchUpdate, CB(handleStackFramePython));
}
//qDebug() << "SECOND CHUNK: " << out;
int pos = out.indexOf("data=");
if (pos != 0) {
- qDebug() << "DISCARDING JUNK AT BEGIN OF RESPONSE: "
- << out.left(pos);
+ showMessage(_("DISCARDING JUNK AT BEGIN OF RESPONSE: "
+ + out.left(pos)));
out = out.mid(pos);
}
GdbMi all;
rebuildWatchModel();
}
} else {
- debugMessage(_("DUMPER FAILED: " + response.toString()));
+ showMessage(_("DUMPER FAILED: " + response.toString()));
}
}
if (m_gdbAdapter->isTrkAdapter())
m_gdbAdapter->trkReloadThreads();
else
- postCommand("-thread-list-ids", CB(handleStackListThreads), 0);
+ postCommand("-thread-list-ids", CB(handleThreadListIds), 0);
manager()->reloadRegisters();
updateLocals();
}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "remotegdbprocess.h"
+
+#include "remoteplaingdbadapter.h"
+
+#include <ctype.h>
+
+namespace Debugger {
+namespace Internal {
+
+RemoteGdbProcess::RemoteGdbProcess(const Core::SshServerInfo &server,
+ RemotePlainGdbAdapter *adapter, QObject *parent)
+ : AbstractGdbProcess(parent), m_serverInfo(server), m_adapter(adapter)
+{
+
+}
+
+QByteArray RemoteGdbProcess::readAllStandardOutput()
+{
+ QByteArray output = m_gdbOutput;
+ m_gdbOutput.clear();
+ return output;
+}
+
+QByteArray RemoteGdbProcess::readAllStandardError()
+{
+ QByteArray errorOutput = m_errorOutput;
+ m_errorOutput.clear();
+ return errorOutput;
+}
+
+void RemoteGdbProcess::start(const QString &cmd, const QStringList &args)
+{
+ m_gdbConn = Core::InteractiveSshConnection::create(m_serverInfo);
+ m_appOutputConn = Core::InteractiveSshConnection::create(m_serverInfo);
+ m_errOutputConn = Core::InteractiveSshConnection::create(m_serverInfo);
+ m_command = cmd;
+ m_cmdArgs = args;
+ m_errOutputConn->start();
+ m_appOutputConn->start();
+ m_gdbConn->start();
+ }
+
+bool RemoteGdbProcess::waitForStarted()
+{
+ if (!waitForInputReady(m_appOutputConn))
+ return false;
+ if (!sendAndWaitForEcho(m_appOutputConn, readerCmdLine(AppOutputFile)))
+ return false;
+ if (!waitForInputReady(m_errOutputConn))
+ return false;
+ if (!sendAndWaitForEcho(m_errOutputConn, readerCmdLine(ErrOutputFile)))
+ return false;
+ if (!waitForInputReady(m_gdbConn))
+ return false;
+ connect(m_appOutputConn.data(), SIGNAL(remoteOutputAvailable()),
+ this, SLOT(handleAppOutput()));
+ connect(m_errOutputConn.data(), SIGNAL(remoteOutputAvailable()),
+ this, SLOT(handleErrOutput()));
+ connect(m_gdbConn.data(), SIGNAL(remoteOutputAvailable()),
+ this, SLOT(handleGdbOutput()));
+ m_gdbStarted = false;
+ m_gdbCmdLine = "stty -echo && DISPLAY=:0.0 " + m_command.toUtf8() + ' '
+ + m_cmdArgs.join(QLatin1String(" ")).toUtf8()
+ + " -tty=" + AppOutputFile + " 2>" + ErrOutputFile + '\n';
+ if (!m_wd.isEmpty())
+ m_gdbCmdLine.prepend("cd " + m_wd.toUtf8() + " && ");
+ if (sendInput(m_gdbCmdLine) != m_gdbCmdLine.count())
+ return false;
+
+ return true;
+}
+
+qint64 RemoteGdbProcess::write(const QByteArray &data)
+{
+ if (!m_gdbStarted || !m_inputToSend.isEmpty() || !m_lastSeqNr.isEmpty()) {
+ m_inputToSend.enqueue(data);
+ return data.size();
+ } else {
+ return sendInput(data);
+ }
+}
+
+void RemoteGdbProcess::kill()
+{
+ stopReaders();
+ Core::InteractiveSshConnection::Ptr controlConn
+ = Core::InteractiveSshConnection::create(m_serverInfo);
+ if (!controlConn->hasError()) {
+ if (controlConn->start())
+ controlConn->sendInput("pkill -x gdb\r\n");
+ }
+
+ m_gdbConn->quit();
+ emit finished(0, QProcess::CrashExit);
+}
+
+QProcess::ProcessState RemoteGdbProcess::state() const
+{
+ return m_gdbStarted ? QProcess::Running : QProcess::Starting;
+}
+
+QString RemoteGdbProcess::errorString() const
+{
+ return m_gdbConn ? m_gdbConn->error() : QString();
+}
+
+void RemoteGdbProcess::handleGdbOutput()
+{
+ m_currentGdbOutput
+ += removeCarriageReturn(m_gdbConn->waitForRemoteOutput(0));
+#if 0
+ qDebug("%s: complete unread output is '%s'", Q_FUNC_INFO, m_currentGdbOutput.data());
+#endif
+ if (checkForGdbExit(m_currentGdbOutput)) {
+ m_currentGdbOutput.clear();
+ return;
+ }
+
+ if (!m_currentGdbOutput.endsWith('\n'))
+ return;
+
+ if (!m_gdbStarted) {
+ const int index = m_currentGdbOutput.indexOf(m_gdbCmdLine);
+ if (index != -1)
+ m_currentGdbOutput.remove(index, m_gdbCmdLine.size());
+ // Note: We can't guarantee that we will match the command line,
+ // because the remote terminal sometimes inserts control characters.
+ // Otherwise we could set m_gdbStarted here.
+ }
+
+ m_gdbStarted = true;
+
+ if (m_currentGdbOutput.contains(m_lastSeqNr + '^'))
+ m_lastSeqNr.clear();
+
+ if (m_lastSeqNr.isEmpty() && !m_inputToSend.isEmpty()) {
+#if 0
+ qDebug("Sending queued command: %s", m_inputToSend.head().data());
+#endif
+ sendInput(m_inputToSend.dequeue());
+ }
+
+ if (!m_currentGdbOutput.isEmpty()) {
+ const int startPos
+ = m_gdbOutput.isEmpty() ? findAnchor(m_currentGdbOutput) : 0;
+ if (startPos != -1) {
+ m_gdbOutput += m_currentGdbOutput.mid(startPos);
+ m_currentGdbOutput.clear();
+ emit readyReadStandardOutput();
+ }
+ }
+}
+
+QProcessEnvironment RemoteGdbProcess::processEnvironment() const
+{
+ return QProcessEnvironment(); // TODO: Provide actual environment.
+}
+
+void RemoteGdbProcess::setProcessEnvironment(const QProcessEnvironment & /* env */)
+{
+ // TODO: Do something.
+}
+
+void RemoteGdbProcess::setEnvironment(const QStringList & /* env */)
+{
+ // TODO: Do something.
+}
+
+void RemoteGdbProcess::setWorkingDirectory(const QString &dir)
+{
+ m_wd = dir;
+}
+
+int RemoteGdbProcess::findAnchor(const QByteArray &data) const
+{
+ for (int pos = 0; pos < data.count(); ++pos) {
+ const char c = data.at(pos);
+ if (isdigit(c) || c == '*' || c == '+' || c == '=' || c == '~'
+ || c == '@' || c == '&' || c == '^')
+ return pos;
+ }
+ return -1;
+}
+
+qint64 RemoteGdbProcess::sendInput(const QByteArray &data)
+{
+ int pos;
+ for (pos = 0; pos < data.size(); ++pos)
+ if (!isdigit(data.at(pos)))
+ break;
+ m_lastSeqNr = data.left(pos);
+ return m_gdbConn->sendInput(data) ? data.size() : 0;
+}
+
+void RemoteGdbProcess::handleAppOutput()
+{
+ m_adapter->handleApplicationOutput(m_appOutputConn->waitForRemoteOutput(0));
+}
+
+void RemoteGdbProcess::handleErrOutput()
+{
+ m_errorOutput += m_errOutputConn->waitForRemoteOutput(0);
+ emit readyReadStandardError();
+}
+
+void RemoteGdbProcess::stopReaders()
+{
+ if (m_appOutputConn) {
+ disconnect(m_appOutputConn.data(), SIGNAL(remoteOutputAvailable()),
+ this, SLOT(handleAppOutput()));
+ m_appOutputConn->sendInput(CtrlC);
+ m_appOutputConn->quit();
+ }
+ if (m_errOutputConn) {
+ disconnect(m_errOutputConn.data(), SIGNAL(remoteOutputAvailable()),
+ this, SLOT(handleErrOutput()));
+ m_errOutputConn->sendInput(CtrlC);
+ m_errOutputConn->quit();
+ }
+}
+
+QByteArray RemoteGdbProcess::readerCmdLine(const QByteArray &file)
+{
+ return "rm -f " + file + " && mkfifo " + file + " && cat " + file + "\r\n";
+}
+
+QByteArray RemoteGdbProcess::removeCarriageReturn(const QByteArray &data)
+{
+ QByteArray output;
+ for (int i = 0; i < data.size(); ++i) {
+ const char c = data.at(i);
+ if (c != '\r')
+ output += c;
+ }
+ return output;
+}
+
+bool RemoteGdbProcess::checkForGdbExit(QByteArray &output)
+{
+ const QByteArray exitString("^exit");
+ const int exitPos = output.indexOf(exitString);
+ if (exitPos == -1)
+ return false;
+
+ emit finished(0, QProcess::NormalExit);
+ disconnect(m_gdbConn.data(), SIGNAL(remoteOutputAvailable()),
+ this, SLOT(handleGdbOutput()));
+ output.remove(exitPos + exitString.size(), output.size());
+ stopReaders();
+ return true;
+}
+
+bool RemoteGdbProcess::waitForInputReady(Core::InteractiveSshConnection::Ptr &conn)
+{
+ if (conn->waitForRemoteOutput(m_serverInfo.timeout).isEmpty())
+ return false;
+ while (!conn->waitForRemoteOutput(100).isEmpty())
+ ;
+ return true;
+}
+
+bool RemoteGdbProcess::sendAndWaitForEcho(Core::InteractiveSshConnection::Ptr &conn,
+ const QByteArray &cmdLine)
+{
+ conn->sendInput(cmdLine);
+ QByteArray allOutput;
+ while (!allOutput.endsWith(cmdLine)) {
+ const QByteArray curOutput = conn->waitForRemoteOutput(100);
+ if (curOutput.isEmpty())
+ return false;
+ allOutput += curOutput;
+ }
+ return true;
+}
+
+
+const QByteArray RemoteGdbProcess::CtrlC = QByteArray(1, 0x3);
+const QByteArray RemoteGdbProcess::AppOutputFile("app_output");
+const QByteArray RemoteGdbProcess::ErrOutputFile("err_output");
+
+} // namespace Internal
+} // namespace Debugger
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef REMOTEGDBPROCESS_H
+#define REMOTEGDBPROCESS_H
+
+#include "abstractgdbprocess.h"
+
+#include <coreplugin/ssh/sshconnection.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QQueue>
+
+namespace Debugger {
+namespace Internal {
+
+class RemotePlainGdbAdapter;
+
+class RemoteGdbProcess : public AbstractGdbProcess
+{
+ Q_OBJECT
+public:
+ RemoteGdbProcess(const Core::SshServerInfo &server,
+ RemotePlainGdbAdapter *adapter, QObject *parent = 0);
+
+ virtual QByteArray readAllStandardOutput();
+ virtual QByteArray readAllStandardError();
+
+ virtual void start(const QString &cmd, const QStringList &args);
+ virtual bool waitForStarted();
+ virtual qint64 write(const QByteArray &data);
+ virtual void kill();
+
+ virtual QProcess::ProcessState state() const;
+ virtual QString errorString() const;
+
+ virtual QProcessEnvironment processEnvironment() const;
+ virtual void setProcessEnvironment(const QProcessEnvironment &env);
+ virtual void setEnvironment(const QStringList &env);
+ virtual void setWorkingDirectory(const QString &dir);
+
+ static const QByteArray CtrlC;
+
+private slots:
+ void handleGdbOutput();
+ void handleAppOutput();
+ void handleErrOutput();
+
+private:
+ static QByteArray readerCmdLine(const QByteArray &file);
+
+ int findAnchor(const QByteArray &data) const;
+ qint64 sendInput(const QByteArray &data);
+ void stopReaders();
+ QByteArray removeCarriageReturn(const QByteArray &data);
+ bool checkForGdbExit(QByteArray &output);
+ bool sendAndWaitForEcho(Core::InteractiveSshConnection::Ptr &conn,
+ const QByteArray &cmdLine);
+ bool waitForInputReady(Core::InteractiveSshConnection::Ptr &conn);
+
+ static const QByteArray AppOutputFile;
+ static const QByteArray ErrOutputFile;
+
+ Core::SshServerInfo m_serverInfo;
+ Core::InteractiveSshConnection::Ptr m_gdbConn;
+ Core::InteractiveSshConnection::Ptr m_appOutputConn;
+ Core::InteractiveSshConnection::Ptr m_errOutputConn;
+ QByteArray m_gdbOutput;
+ QByteArray m_errorOutput;
+ QString m_command;
+ QStringList m_cmdArgs;
+ QString m_wd;
+ QQueue<QByteArray> m_inputToSend;
+ QByteArray m_currentGdbOutput;
+ QByteArray m_lastSeqNr;
+ QByteArray m_gdbCmdLine;
+ bool m_gdbStarted;
+
+ RemotePlainGdbAdapter *m_adapter;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // REMOTEGDBPROCESS_H
**
**************************************************************************/
-#include "remotegdbadapter.h"
+#include "remotegdbserveradapter.h"
#include "debuggerstringutils.h"
#include "gdbengine.h"
namespace Internal {
#define CB(callback) \
- static_cast<GdbEngine::AdapterCallback>(&RemoteGdbAdapter::callback), \
+ static_cast<GdbEngine::AdapterCallback>(&RemoteGdbServerAdapter::callback), \
STRINGIFY(callback)
///////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////
-RemoteGdbAdapter::RemoteGdbAdapter(GdbEngine *engine, int toolChainType, QObject *parent) :
+RemoteGdbServerAdapter::RemoteGdbServerAdapter(GdbEngine *engine, int toolChainType, QObject *parent) :
AbstractGdbAdapter(engine, parent),
m_toolChainType(toolChainType)
{
this, SLOT(readUploadStandardError()));
}
-AbstractGdbAdapter::DumperHandling RemoteGdbAdapter::dumperHandling() const
+AbstractGdbAdapter::DumperHandling RemoteGdbServerAdapter::dumperHandling() const
{
switch (m_toolChainType) {
case ProjectExplorer::ToolChain::MinGW:
return DumperLoadedByGdbPreload;
}
-void RemoteGdbAdapter::startAdapter()
+void RemoteGdbServerAdapter::startAdapter()
{
QTC_ASSERT(state() == EngineStarting, qDebug() << state());
setState(AdapterStarting);
- debugMessage(_("TRYING TO START ADAPTER"));
+ showMessage(_("TRYING TO START ADAPTER"));
// FIXME: make asynchroneous
// Start the remote server
if (startParameters().serverStartScript.isEmpty()) {
- m_engine->showStatusMessage(_("No server start script given. "
- "Assuming server runs already."));
+ showMessage(_("No server start script given. "
+ "Assuming server runs already."), StatusBar);
} else {
m_uploadProc.start(_("/bin/sh ") + startParameters().serverStartScript);
m_uploadProc.waitForStarted();
emit adapterStarted();
}
-void RemoteGdbAdapter::uploadProcError(QProcess::ProcessError error)
+void RemoteGdbServerAdapter::uploadProcError(QProcess::ProcessError error)
{
QString msg;
switch (error) {
"This is the default return value of error().");
}
- m_engine->showStatusMessage(msg);
+ showMessage(msg, StatusBar);
showMessageBox(QMessageBox::Critical, tr("Error"), msg);
}
-void RemoteGdbAdapter::readUploadStandardOutput()
+void RemoteGdbServerAdapter::readUploadStandardOutput()
{
- QByteArray ba = m_uploadProc.readAllStandardOutput();
- m_engine->showDebuggerOutput(LogOutput, QString::fromLocal8Bit(ba, ba.length()));
+ const QByteArray ba = m_uploadProc.readAllStandardOutput();
+ const QString msg = QString::fromLocal8Bit(ba, ba.length());
+ showMessage(msg, LogOutput);
+ showMessage(msg, AppOutput);
}
-void RemoteGdbAdapter::readUploadStandardError()
+void RemoteGdbServerAdapter::readUploadStandardError()
{
- QByteArray ba = m_uploadProc.readAllStandardError();
- m_engine->showDebuggerOutput(LogError, QString::fromLocal8Bit(ba, ba.length()));
+ const QByteArray ba = m_uploadProc.readAllStandardError();
+ const QString msg = QString::fromLocal8Bit(ba, ba.length());
+ showMessage(msg, LogOutput);
+ showMessage(msg, AppError);
}
-void RemoteGdbAdapter::startInferior()
+void RemoteGdbServerAdapter::startInferior()
{
QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
CB(handleFileExecAndSymbols));
}
-void RemoteGdbAdapter::handleSetTargetAsync(const GdbResponse &response)
+void RemoteGdbServerAdapter::handleSetTargetAsync(const GdbResponse &response)
{
QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
if (response.resultClass == GdbResultError)
qDebug() << "Adapter too old: does not support asynchronous mode.";
}
-void RemoteGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
+void RemoteGdbServerAdapter::handleFileExecAndSymbols(const GdbResponse &response)
{
QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
if (response.resultClass == GdbResultDone) {
}
}
-void RemoteGdbAdapter::handleTargetRemote(const GdbResponse &record)
+void RemoteGdbServerAdapter::handleTargetRemote(const GdbResponse &record)
{
QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
if (record.resultClass == GdbResultDone) {
setState(InferiorStopped);
// gdb server will stop the remote application itself.
- debugMessage(_("INFERIOR STARTED"));
- showStatusMessage(msgAttachedToStoppedInferior());
+ showMessage(_("INFERIOR STARTED"));
+ showMessage(msgAttachedToStoppedInferior(), StatusBar);
emit inferiorPrepared();
} else {
// 16^error,msg="hd:5555: Connection timed out."
}
}
-void RemoteGdbAdapter::startInferiorPhase2()
+void RemoteGdbServerAdapter::startInferiorPhase2()
{
m_engine->continueInferiorInternal();
}
-void RemoteGdbAdapter::interruptInferior()
+void RemoteGdbServerAdapter::interruptInferior()
{
// FIXME: On some gdb versions like git 170ffa5d7dd this produces
// >810^error,msg="mi_cmd_exec_interrupt: Inferior not executing."
m_engine->postCommand("-exec-interrupt", GdbEngine::Immediate);
}
-void RemoteGdbAdapter::shutdown()
+void RemoteGdbServerAdapter::shutdown()
{
// FIXME: cleanup missing
}
#include "abstractgdbadapter.h"
+#include "abstractgdbprocess.h"
+
namespace Debugger {
namespace Internal {
//
///////////////////////////////////////////////////////////////////////
-class RemoteGdbAdapter : public AbstractGdbAdapter
+class RemoteGdbServerAdapter : public AbstractGdbAdapter
{
Q_OBJECT
public:
- RemoteGdbAdapter(GdbEngine *engine, int toolChainType, QObject *parent = 0);
+ RemoteGdbServerAdapter(GdbEngine *engine, int toolChainType, QObject *parent = 0);
virtual DumperHandling dumperHandling() const;
void startInferiorPhase2();
void interruptInferior();
void shutdown();
+ AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
private:
Q_SLOT void readUploadStandardOutput();
const int m_toolChainType;
QProcess m_uploadProc;
+ LocalGdbProcess m_gdbProc;
};
} // namespace Internal
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "remoteplaingdbadapter.h"
+
+#include <debugger/debuggeractions.h>
+#include <debugger/debuggerstringutils.h>
+#include <utils/qtcassert.h>
+
+
+namespace Debugger {
+namespace Internal {
+
+RemotePlainGdbAdapter::RemotePlainGdbAdapter(GdbEngine *engine,
+ QObject *parent)
+ : AbstractPlainGdbAdapter(engine, parent),
+ m_gdbProc(engine->startParameters().sshserver, this)
+{
+}
+
+void RemotePlainGdbAdapter::startAdapter()
+{
+ QTC_ASSERT(state() == EngineStarting, qDebug() << state());
+ setState(AdapterStarting);
+ showMessage(QLatin1String("TRYING TO START ADAPTER"));
+
+ if (!startParameters().workingDirectory.isEmpty())
+ m_gdbProc.setWorkingDirectory(startParameters().workingDirectory);
+ if (!startParameters().environment.isEmpty())
+ m_gdbProc.setEnvironment(startParameters().environment);
+
+ if (m_engine->startGdb(QStringList(), m_engine->startParameters().debuggerCommand))
+ emit adapterStarted();
+}
+
+void RemotePlainGdbAdapter::interruptInferior()
+{
+ m_gdbProc.write(RemoteGdbProcess::CtrlC);
+}
+
+QByteArray RemotePlainGdbAdapter::execFilePath() const
+{
+ return startParameters().executable.toUtf8();
+}
+
+bool RemotePlainGdbAdapter::infoTargetNecessary() const
+{
+ return true;
+}
+
+QByteArray RemotePlainGdbAdapter::toLocalEncoding(const QString &s) const
+{
+ return s.toUtf8();
+}
+
+QString RemotePlainGdbAdapter::fromLocalEncoding(const QByteArray &b) const
+{
+ return QString::fromUtf8(b);
+}
+
+void RemotePlainGdbAdapter::handleApplicationOutput(const QByteArray &output)
+{
+ // FIXME: Remote encoding?
+ showMessage(QString::fromLatin1(output), AppOutput);
+}
+
+} // namespace Internal
+} // namespace Debugger
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef REMOTEGDBCLIENTADAPTER_H
+#define REMOTEGDBCLIENTADAPTER_H
+
+#include "abstractplaingdbadapter.h"
+#include "remotegdbprocess.h"
+
+namespace Debugger {
+namespace Internal {
+
+class RemotePlainGdbAdapter : public AbstractPlainGdbAdapter
+{
+ Q_OBJECT
+ friend class RemoteGdbProcess;
+public:
+ RemotePlainGdbAdapter(GdbEngine *engine, QObject *parent = 0);
+
+ virtual void startAdapter();
+ virtual void interruptInferior();
+ virtual AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
+ virtual DumperHandling dumperHandling() const { return DumperLoadedByGdbPreload; }
+
+private:
+ virtual QByteArray execFilePath() const;
+ virtual bool infoTargetNecessary() const;
+ virtual QByteArray toLocalEncoding(const QString &s) const;
+ virtual QString fromLocalEncoding(const QByteArray &b) const;
+ void handleApplicationOutput(const QByteArray &output);
+
+ RemoteGdbProcess m_gdbProc;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // REMOTEGDBCLIENTADAPTER_H
{
QTC_ASSERT(state() == EngineStarting, qDebug() << state());
setState(AdapterStarting);
- debugMessage(_("TRYING TO START ADAPTER"));
+ showMessage(_("TRYING TO START ADAPTER"));
// Currently, adapters are not re-used
// // We leave the console open, so recycle it now.
// m_stubProc.stop();
// m_stubProc.blockSignals(false);
- m_stubProc.setWorkingDirectory(startParameters().workingDir);
+ m_stubProc.setWorkingDirectory(startParameters().workingDirectory);
// Set environment + dumper preload.
QStringList environment = startParameters().environment;
m_stubProc.setEnvironment(environment);
QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
if (response.resultClass == GdbResultDone) {
setState(InferiorStopped);
- debugMessage(_("INFERIOR ATTACHED"));
+ showMessage(_("INFERIOR ATTACHED"));
emit inferiorPrepared();
#ifdef Q_OS_LINUX
m_engine->postCommand("-stack-list-frames 0 0", CB(handleEntryPoint));
const qint64 attachedPID = m_engine->inferiorPid();
QTC_ASSERT(attachedPID > 0, return);
if (!interruptProcess(attachedPID))
- debugMessage(_("CANNOT INTERRUPT %1").arg(attachedPID));
+ showMessage(_("CANNOT INTERRUPT %1").arg(attachedPID));
}
void TermGdbAdapter::stubMessage(const QString &msg, bool)
void TermGdbAdapter::stubExited()
{
- debugMessage(_("STUB EXITED"));
+ showMessage(_("STUB EXITED"));
if (state() != AdapterStarting // From previous instance
&& state() != EngineShuttingDown && state() != DebuggerNotReady)
emit adapterCrashed(QString());
#include "abstractgdbadapter.h"
+#include "abstractgdbprocess.h"
+
#include <consoleprocess.h>
namespace Debugger {
void startInferior();
void startInferiorPhase2();
void interruptInferior();
+ AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
private:
void handleStubAttached(const GdbResponse &response);
Q_SLOT void stubMessage(const QString &msg, bool isError);
Utils::ConsoleProcess m_stubProc;
+ LocalGdbProcess m_gdbProc;
};
} // namespace Internal
#include "bluetoothlistener_gui.h"
#include "registerhandler.h"
-#include "stackhandler.h"
+#include "threadshandler.h"
#include "debuggeractions.h"
#include "debuggerstringutils.h"
#include "watchutils.h"
if (from <= pc && pc <= to) {
//to = qMax(to - 4, from);
//to = qMax(to - 4, from);
- debugMessage("STEP IN " + hexxNumber(from) + " " + hexxNumber(to)
+ showMessage("STEP IN " + hexxNumber(from) + " " + hexxNumber(to)
+ " INSTEAD OF " + hexxNumber(pc));
} else {
from = pc;
void TrkGdbAdapter::logMessage(const QString &msg)
{
if (m_verbose)
- debugMessage("TRK LOG: " + msg);
+ showMessage("TRK LOG: " + msg);
}
//
}
case TrkNotifyStopped: { // 0x90 Notified Stopped
// 90 01 78 6a 40 40 00 00 07 23 00 00 07 24 00 00
- debugMessage(_("RESET SNAPSHOT (NOTIFY STOPPED)"));
+ showMessage(_("RESET SNAPSHOT (NOTIFY STOPPED)"));
m_snapshot.reset();
QString reason;
uint addr;
trk::Launcher::parseNotifyStopped(result.data, &pid, &tid, &addr, &reason);
const QString msg = trk::Launcher::msgStopped(pid, tid, addr, reason);
logMessage(prefix + msg);
- m_engine->manager()->showDebuggerOutput(LogMisc, msg);
+ showMessage(msg, LogMisc);
sendTrkAck(result.token);
if (addr) {
// Todo: Do not send off GdbMessages if a synced gdb
logMessage(QLatin1String("Ignoring stop at 0"));
}
- #if 1
+# if 1
// We almost always need register values, so get them
// now before informing gdb about the stop.s
//qDebug() << "Auto-fetching registers";
sendTrkMessage(0x12,
TrkCB(handleAndReportReadRegistersAfterStop),
trkReadRegistersMessage());
- #else
+# else
// As a source-line step typically consists of
// several instruction steps, better avoid the multiple
// roundtrips through TRK in favour of an additional
// roundtrip through gdb. But gdb will ask for all registers.
- #if 1
+# if 1
sendGdbServerMessage("S05", "Target stopped");
- #else
+# else
QByteArray ba = "T05";
appendRegister(&ba, RegisterPSGdb, addr);
sendGdbServerMessage(ba, "Registers");
- #endif
- #endif
+# endif
+# endif
break;
}
case TrkNotifyException: { // 0x91 Notify Exception (obsolete)
- debugMessage(_("RESET SNAPSHOT (NOTIFY EXCEPTION)"));
+ showMessage(_("RESET SNAPSHOT (NOTIFY EXCEPTION)"));
m_snapshot.reset();
logMessage(prefix + "NOTE: EXCEPTION " + str);
sendTrkAck(result.token);
break;
}
case 0x92: { //
- debugMessage(_("RESET SNAPSHOT (NOTIFY INTERNAL ERROR)"));
+ showMessage(_("RESET SNAPSHOT (NOTIFY INTERNAL ERROR)"));
m_snapshot.reset();
logMessage(prefix + "NOTE: INTERNAL ERROR: " + str);
sendTrkAck(result.token);
case 0xa0: { // Notify Created
// Sending this ACK does not seem to make a difference. Why?
//sendTrkAck(result.token);
- debugMessage(_("RESET SNAPSHOT (NOTIFY CREATED)"));
+ showMessage(_("RESET SNAPSHOT (NOTIFY CREATED)"));
m_snapshot.fullReset();
const char *data = result.data.data();
const trk::byte error = result.data.at(0);
}
// Happens when chunks are not combined
QTC_ASSERT(false, /**/);
- debugMessage("CHUNKS NOT COMBINED");
- #ifdef MEMORY_DEBUG
+ showMessage("CHUNKS NOT COMBINED");
+# ifdef MEMORY_DEBUG
qDebug() << "CHUNKS NOT COMBINED";
it = m_snapshot.memory.begin();
et = m_snapshot.memory.end();
for ( ; it != et; ++it)
qDebug() << hexNumber(it.key().from) << hexNumber(it.key().to);
qDebug() << "WANTED" << wanted.from << wanted.to;
- #endif
+# endif
sendGdbServerMessage("E22", "");
return;
}
logMessage("ERROR: " + result.errorString() + " in handleStep");
// Try fallback with Continue.
- debugMessage("FALLBACK TO 'CONTINUE'");
+ showMessage("FALLBACK TO 'CONTINUE'");
sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE");
//sendGdbServerMessage("S05", "Stepping finished");
// Start
QTC_ASSERT(state() == EngineStarting, qDebug() << state());
setState(AdapterStarting);
- debugMessage(_("TRYING TO START ADAPTER"));
+ showMessage(_("TRYING TO START ADAPTER"));
logMessage(QLatin1String("### Starting TrkGdbAdapter"));
// Prompt the user to start communication
trkReadMemoryMessage(m_session.dataseg, 12));
return;
}
- m_engine->m_gdbProc.write(data);
+ m_gdbProc.write(data);
}
uint oldPC;
#include "trkutils.h"
#include "trkdevice.h"
#include "launcher.h"
+#include "abstractgdbprocess.h"
#include <QtCore/QHash>
#include <QtCore/QPointer>
void startInferiorPhase2();
void interruptInferior();
void shutdown();
+ AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
void cleanup();
void emitDelayedInferiorStartFailed(const QString &msg);
QString m_symbolFile;
int m_verbose;
bool m_bufferedMemoryRead;
+ LocalGdbProcess m_gdbProc;
};
} // namespace Internal
#include "idebuggerengine.h"
#include "debuggermanager.h"
+#include <utils/qtcassert.h>
+
namespace Debugger {
namespace Internal {
return true;
}
-void IDebuggerEngine::showDebuggerInput(int channel, const QString &msg)
-{
- m_manager->showDebuggerInput(channel, msg);
-}
-
-void IDebuggerEngine::showDebuggerOutput(int channel, const QString &msg)
+void IDebuggerEngine::showMessage(const QString &msg, int channel, int timeout) const
{
- m_manager->showDebuggerOutput(channel, msg);
+ QTC_ASSERT(runControl(), return);
+ runControl()->showMessage(msg, channel, timeout);
}
} // namespace Internal
}
namespace Debugger {
+
class DebuggerManager;
-class DebuggerStartParameters;
+class DebuggerRunControl;
+
namespace Internal {
class DisassemblerViewAgent;
Q_OBJECT
public:
- typedef QSharedPointer<DebuggerStartParameters> DebuggerStartParametersPtr;
-
IDebuggerEngine(DebuggerManager *manager, QObject *parent = 0)
- : QObject(parent), m_manager(manager)
+ : QObject(parent), m_manager(manager), m_runControl()
{}
+ // FIXME: Move this to DebuggerEngineFactory::create(); ?
+ void setRunControl(DebuggerRunControl *runControl)
+ { m_runControl = runControl; }
+ DebuggerRunControl *runControl() const
+ { return m_runControl; }
+
virtual void shutdown() = 0;
virtual void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos) = 0;
- virtual void startDebugger(const DebuggerStartParametersPtr &startParameters) = 0;
+ virtual void startDebugger() = 0;
virtual void exitDebugger() = 0;
virtual void abortDebugger() { exitDebugger(); }
virtual void detachDebugger() {}
virtual void reloadModules() = 0;
virtual void loadSymbols(const QString &moduleName) = 0;
virtual void loadAllSymbols() = 0;
- virtual QList<Symbol> moduleSymbols(const QString &moduleName) = 0;
+ virtual void requestModuleSymbols(const QString &moduleName) = 0;
virtual void reloadRegisters() = 0;
virtual bool isSynchroneous() const { return false; }
virtual QString qtNamespace() const { return QString(); }
+public slots:
// Convenience
- void showDebuggerInput(int channel, const QString &msg);
- void showDebuggerOutput(int channel, const QString &msg);
+ void showMessage(const QString &msg, int channel = LogDebug, int timeout = -1) const;
+ void showStatusMessage(const QString &msg, int timeout = -1) const
+ { showMessage(msg, StatusBar, timeout); }
+ DebuggerManager *manager() const { return m_manager; }
protected:
- void showStatusMessage(const QString &msg, int timeout = -1);
DebuggerState state() const;
void setState(DebuggerState state, bool forced = false);
- DebuggerManager *manager() const { return m_manager; }
DebuggerManager *m_manager;
+ DebuggerRunControl *m_runControl;
signals:
void startSuccessful();
// QAbstractItemModel
int columnCount(const QModelIndex &parent) const
- { return parent.isValid() ? 0 : 4; }
+ { return parent.isValid() ? 0 : 5; }
int rowCount(const QModelIndex &parent) const
{ return parent.isValid() ? 0 : m_modules.size(); }
QModelIndex parent(const QModelIndex &) const { return QModelIndex(); }
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
static QString headers[] = {
tr("Module name") + " ",
+ tr("Module path") + " ",
tr("Symbols read") + " ",
tr("Start address") + " ",
tr("End address") + " "
break;
case 1:
if (role == Qt::DisplayRole)
- return module.symbolsRead ? m_yes : m_no;
+ return module.modulePath;
break;
case 2:
if (role == Qt::DisplayRole)
- return module.startAddress;
+ return module.symbolsRead ? m_yes : m_no;
break;
case 3:
if (role == Qt::DisplayRole)
+ return module.startAddress;
+ break;
+ case 4:
+ if (role == Qt::DisplayRole)
return module.endAddress;
break;
}
public:
QString moduleName;
+ QString modulePath;
bool symbolsRead;
QString startAddress;
QString endAddress;
resizeColumnToContents(0);
resizeColumnToContents(1);
resizeColumnToContents(2);
+ resizeColumnToContents(3);
}
void ModulesWindow::setAlwaysResizeColumnsToContents(bool on)
header()->setResizeMode(1, mode);
header()->setResizeMode(2, mode);
header()->setResizeMode(3, mode);
+ header()->setResizeMode(4, mode);
//setColumnHidden(3, true);
}
void ModulesWindow::showSymbols(const QString &name)
{
- if (name.isEmpty())
- return;
- QApplication::setOverrideCursor(Qt::WaitCursor);
- const QList<Symbol> symbols = m_debuggerManager->moduleSymbols(name);
- QApplication::restoreOverrideCursor();
- if (symbols.empty())
- return;
- QTreeWidget *w = new QTreeWidget;
- w->setColumnCount(3);
- w->setRootIsDecorated(false);
- w->setAlternatingRowColors(true);
- w->setHeaderLabels(QStringList() << tr("Address") << tr("Code") << tr("Symbol"));
- w->setWindowTitle(tr("Symbols in \"%1\"").arg(name));
- foreach (const Symbol &s, symbols) {
- QTreeWidgetItem *it = new QTreeWidgetItem;
- it->setData(0, Qt::DisplayRole, s.address);
- it->setData(1, Qt::DisplayRole, s.state);
- it->setData(2, Qt::DisplayRole, s.name);
- w->addTopLevelItem(it);
- }
- emit newDockRequested(w);
+ if (!name.isEmpty())
+ m_debuggerManager->requestModuleSymbols(name);
}
} // namespace Internal
{
XSDEBUG("PdbEngine::executeDebuggerCommand:" << command);
if (state() == DebuggerNotReady) {
- debugMessage(_("PDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command);
+ showMessage(_("PDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command);
return;
}
m_pdbProc.write(command.toLatin1() + "\n");
cmd.callbackName = callbackName;
cmd.cookie = cookie;
m_commands.enqueue(cmd);
- showDebuggerInput(LogMisc, _(cmd.command));
+ showMessage(_(cmd.command), LogInput);
m_pdbProc.write(cmd.command + "\n");
}
setState(DebuggerNotReady);
}
-void PdbEngine::startDebugger(const DebuggerStartParametersPtr &sp)
+void PdbEngine::startDebugger()
{
+ QTC_ASSERT(runControl(), return);
setState(AdapterStarting);
- m_scriptFileName = QFileInfo(sp->executable).absoluteFilePath();
+ m_scriptFileName = QFileInfo(runControl()->sp().executable).absoluteFilePath();
QFile scriptFile(m_scriptFileName);
if (!scriptFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
- //debugMessage("STARTING " +m_scriptFileName + "FAILED");
- manager()->showDebuggerOutput(LogError, QString::fromLatin1("Cannot open %1: %2").
- arg(m_scriptFileName, scriptFile.errorString()));
+ //showMessage("STARTING " +m_scriptFileName + "FAILED");
+ showMessage(QString::fromLatin1("Cannot open %1: %2").
+ arg(m_scriptFileName, scriptFile.errorString()), LogError);
emit startFailed();
return;
}
m_pdbProc.disconnect(); // From any previous runs
m_pdb = _("/usr/bin/python");
- debugMessage(_("STARTING PDB ") + m_pdb);
+ showMessage(_("STARTING PDB ") + m_pdb);
QStringList gdbArgs;
gdbArgs += _("-i");
gdbArgs += _("/usr/bin/pdb");
const QString msg = tr("Unable to start pdb '%1': %2")
.arg(m_pdb, m_pdbProc.errorString());
setState(AdapterStartFailed);
- debugMessage(_("ADAPTER START FAILED"));
+ showMessage(_("ADAPTER START FAILED"));
if (!msg.isEmpty()) {
const QString title = tr("Adapter start failed");
Core::ICore::instance()->showWarningWithOptions(title, msg);
setState(InferiorRunning);
attemptBreakpointSynchronization();
- debugMessage(_("PDB STARTED, INITIALIZING IT"));
+ showMessage(_("PDB STARTED, INITIALIZING IT"));
const QByteArray dumperSourcePath =
Core::ICore::instance()->resourcePath().toLocal8Bit() + "/gdbmacros/";
postCommand("execfile('" + dumperSourcePath + "pdumper.py')",
void PdbEngine::reloadModules()
{
+ postCommand("qdebug('listmodules')", CB(handleListModules));
+}
+
+void PdbEngine::handleListModules(const PdbResponse &response)
+{
+ GdbMi out;
+ out.fromString(response.data.trimmed());
+ QList<Module> modules;
+ foreach (const GdbMi &item, out.children()) {
+ Module module;
+ module.moduleName = _(item.findChild("name").data());
+ QString path = _(item.findChild("value").data());
+ int pos = path.indexOf(_("' from '"));
+ if (pos != -1) {
+ path = path.mid(pos + 8);
+ if (path.size() >= 2)
+ path.chop(2);
+ } else if (path.startsWith(_("<module '"))
+ && path.endsWith(_("' (built-in)>"))) {
+ path = _("(builtin)");
+ }
+ module.modulePath = path;
+ modules.append(module);
+ }
+ manager()->modulesHandler()->setModules(modules);
}
-QList<Symbol> PdbEngine::moduleSymbols(const QString & /*moduleName*/)
+void PdbEngine::requestModuleSymbols(const QString &moduleName)
{
- return QList<Symbol>();
+ postCommand("qdebug('listsymbols','" + moduleName.toLatin1() + "')",
+ CB(handleListSymbols), moduleName);
}
+void PdbEngine::handleListSymbols(const PdbResponse &response)
+{
+ GdbMi out;
+ out.fromString(response.data.trimmed());
+ QList<Symbol> symbols;
+ QString moduleName = response.cookie.toString();
+ foreach (const GdbMi &item, out.children()) {
+ Symbol symbol;
+ symbol.name = _(item.findChild("name").data());
+ symbols.append(symbol);
+ }
+ manager()->showModuleSymbols(moduleName, symbols);
+}
//////////////////////////////////////////////////////////////////////
//
void PdbEngine::handlePdbError(QProcess::ProcessError error)
{
- debugMessage(_("HANDLE PDB ERROR"));
+ showMessage(_("HANDLE PDB ERROR"));
switch (error) {
case QProcess::Crashed:
break; // will get a processExited() as well
void PdbEngine::handlePdbFinished(int code, QProcess::ExitStatus type)
{
- debugMessage(_("PDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
+ showMessage(_("PDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
//shutdown();
//initializeVariables();
setState(DebuggerNotReady, true);
{
QByteArray err = m_pdbProc.readAllStandardError();
qWarning() << "Unexpected pdb stderr:" << err;
- showDebuggerOutput(LogDebug, _("Unexpected pdb stderr: " + err));
+ showMessage(_("Unexpected pdb stderr: " + err));
}
void PdbEngine::readPdbStandardOutput()
while ((pos = m_inbuffer.indexOf("(Pdb)")) != -1) {
PdbResponse response;
response.data = m_inbuffer.left(pos).trimmed();
- showDebuggerOutput(LogDebug, _(response.data));
+ showMessage(_(response.data));
m_inbuffer = m_inbuffer.mid(pos + 6);
QTC_ASSERT(!m_commands.isEmpty(),
qDebug() << "RESPONSE: " << response.data; return)
continueInferior();
}
-void PdbEngine::debugMessage(const QString &msg)
+unsigned PdbEngine::debuggerCapabilities() const
{
- showDebuggerOutput(LogDebug, msg);
+ return ReloadModuleCapability;
}
IDebuggerEngine *createPdbEngine(DebuggerManager *manager)
void shutdown();
void setToolTipExpression(const QPoint &mousePos,
TextEditor::ITextEditor *editor, int cursorPos);
- void startDebugger(const DebuggerStartParametersPtr &sp);
+ void startDebugger();
void exitDebugger();
void loadSymbols(const QString &moduleName);
void loadAllSymbols();
- virtual QList<Symbol> moduleSymbols(const QString &moduleName);
+ void requestModuleSymbols(const QString &moduleName);
void reloadModules();
void reloadRegisters() {}
void reloadSourceFiles() {}
void updateWatchData(const WatchData &data);
private:
- void debugMessage(const QString &msg);
QString errorMessage(QProcess::ProcessError error) const;
+ unsigned debuggerCapabilities() const;
Q_SLOT void handlePdbFinished(int, QProcess::ExitStatus status);
Q_SLOT void handlePdbError(QProcess::ProcessError error);
void handleStop(const PdbResponse &response);
void handleBacktrace(const PdbResponse &response);
void handleListLocals(const PdbResponse &response);
+ void handleListModules(const PdbResponse &response);
+ void handleListSymbols(const PdbResponse &response);
void handleLoadDumper(const PdbResponse &response);
void handleBreakInsert(const PdbResponse &response);
--- /dev/null
+HEADERS += \
+ $$PWD/qmlengine.h \
+
+SOURCES += \
+ $$PWD/qmlengine.cpp \
+
+FORMS +=
+
+RESOURCES +=
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "qmlengine.h"
+
+#include "debuggerstringutils.h"
+#include "debuggerdialogs.h"
+#include "breakhandler.h"
+#include "debuggerconstants.h"
+#include "debuggermanager.h"
+#include "moduleshandler.h"
+#include "registerhandler.h"
+#include "stackhandler.h"
+#include "watchhandler.h"
+#include "watchutils.h"
+#include "moduleshandler.h"
+
+#include <utils/qtcassert.h>
+
+#include <QtCore/QDateTime>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTimer>
+
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QMainWindow>
+#include <QtGui/QMessageBox>
+#include <QtGui/QToolTip>
+
+#include <QtNetwork/QTcpSocket>
+
+#define DEBUG_QML 1
+#if DEBUG_QML
+# define SDEBUG(s) qDebug() << s
+#else
+# define SDEBUG(s)
+#endif
+# define XSDEBUG(s) qDebug() << s
+
+#define CB(callback) &QmlEngine::callback, STRINGIFY(callback)
+
+//#define USE_CONGESTION_CONTROL
+
+
+namespace Debugger {
+namespace Internal {
+
+
+class QmlResponse
+{
+public:
+ QmlResponse() {}
+ QmlResponse(const QByteArray &data_) : data(data_) {}
+
+ QString toString() const { return data; }
+
+ QByteArray data;
+};
+
+///////////////////////////////////////////////////////////////////////
+//
+// QmlCommand
+//
+///////////////////////////////////////////////////////////////////////
+
+
+QString QmlEngine::QmlCommand::toString() const
+{
+ return quoteUnprintableLatin1(command);
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// QmlEngine
+//
+///////////////////////////////////////////////////////////////////////
+
+QmlEngine::QmlEngine(DebuggerManager *manager)
+ : IDebuggerEngine(manager)
+{
+ m_congestion = 0;
+ m_inAir = 0;
+
+ m_sendTimer.setSingleShot(true);
+ m_sendTimer.setInterval(100); // ms
+ connect(&m_sendTimer, SIGNAL(timeout()), this, SLOT(handleSendTimer()));
+
+ m_socket = new QTcpSocket(this);
+ connect(m_socket, SIGNAL(connected()), this, SLOT(socketConnected()));
+ connect(m_socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
+ connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ this, SLOT(socketError(QAbstractSocket::SocketError)));
+
+ //void aboutToClose ()
+ //void bytesWritten ( qint64 bytes )
+ //void readChannelFinished ()
+ connect(m_socket, SIGNAL(readyRead()), this, SLOT(socketReadyRead()));
+
+ //connect(m_socket, SIGNAL(hostFound())
+ //connect(m_socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy, QAuthenticator *)))
+ //connect(m_socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ // thism SLOT(socketStateChanged(QAbstractSocket::SocketState)));
+}
+
+QmlEngine::~QmlEngine()
+{
+}
+
+void QmlEngine::socketReadyRead()
+{
+ //XSDEBUG("QmlEngine::socketReadyRead()");
+ m_inbuffer.append(m_socket->readAll());
+ int pos = 0;
+ while (1) {
+ // the "\3" is followed by either "\1" or "\2"
+ int next = m_inbuffer.indexOf("\3", pos);
+ //qDebug() << "pos: " << pos << "next: " << next;
+ if (next == -1)
+ break;
+ handleResponse(m_inbuffer.mid(pos, next - pos));
+ pos = next + 2;
+ }
+ m_inbuffer.clear();
+}
+
+void QmlEngine::socketConnected()
+{
+ showStatusMessage("Socket connected.");
+ m_socket->waitForConnected(2000);
+ //sendCommand("Locator", "redirect", "ID");
+}
+
+void QmlEngine::socketDisconnected()
+{
+ XSDEBUG("FIXME: QmlEngine::socketDisconnected()");
+}
+
+void QmlEngine::socketError(QAbstractSocket::SocketError)
+{
+ QString msg = tr("%1.").arg(m_socket->errorString());
+ //QMessageBox::critical(q->mainWindow(), tr("Error"), msg);
+ showStatusMessage(msg);
+ manager()->notifyInferiorExited();
+}
+
+void QmlEngine::executeDebuggerCommand(const QString &command)
+{
+ QByteArray cmd = command.toUtf8();
+ cmd = cmd.mid(cmd.indexOf(' ') + 1);
+ QByteArray null;
+ null.append('\0');
+ // FIXME: works for single-digit escapes only
+ cmd.replace("\\0", null);
+ cmd.replace("\\1", "\1");
+ cmd.replace("\\3", "\3");
+ QmlCommand tcf;
+ tcf.command = cmd;
+ enqueueCommand(tcf);
+}
+
+void QmlEngine::shutdown()
+{
+ m_congestion = 0;
+ m_inAir = 0;
+ m_services.clear();
+ exitDebugger();
+}
+
+void QmlEngine::exitDebugger()
+{
+ SDEBUG("QmlEngine::exitDebugger()");
+ manager()->notifyInferiorExited();
+}
+
+void QmlEngine::startDebugger()
+{
+ QTC_ASSERT(runControl(), return);
+ qDebug() << "STARTING QML ENGINE";
+ setState(InferiorRunningRequested);
+ showStatusMessage(tr("Running requested..."), 5000);
+ const DebuggerStartParameters &sp = runControl()->sp();
+ const int pos = sp.remoteChannel.indexOf(QLatin1Char(':'));
+ const QString host = sp.remoteChannel.left(pos);
+ const quint16 port = sp.remoteChannel.mid(pos + 1).toInt();
+ //QTimer::singleShot(0, this, SLOT(runInferior()));
+ m_socket->connectToHost(host, port);
+ emit startSuccessful();
+}
+
+void QmlEngine::continueInferior()
+{
+ SDEBUG("QmlEngine::continueInferior()");
+}
+
+void QmlEngine::runInferior()
+{
+}
+
+void QmlEngine::interruptInferior()
+{
+ XSDEBUG("QmlEngine::interruptInferior()");
+}
+
+void QmlEngine::executeStep()
+{
+ //SDEBUG("QmlEngine::executeStep()");
+}
+
+void QmlEngine::executeStepI()
+{
+ //SDEBUG("QmlEngine::executeStepI()");
+}
+
+void QmlEngine::executeStepOut()
+{
+ //SDEBUG("QmlEngine::executeStepOut()");
+}
+
+void QmlEngine::executeNext()
+{
+ //SDEBUG("QmlEngine::nextExec()");
+}
+
+void QmlEngine::executeNextI()
+{
+ //SDEBUG("QmlEngine::executeNextI()");
+}
+
+void QmlEngine::executeRunToLine(const QString &fileName, int lineNumber)
+{
+ Q_UNUSED(fileName)
+ Q_UNUSED(lineNumber)
+ SDEBUG("FIXME: QmlEngine::executeRunToLine()");
+}
+
+void QmlEngine::executeRunToFunction(const QString &functionName)
+{
+ Q_UNUSED(functionName)
+ XSDEBUG("FIXME: QmlEngine::executeRunToFunction()");
+}
+
+void QmlEngine::executeJumpToLine(const QString &fileName, int lineNumber)
+{
+ Q_UNUSED(fileName)
+ Q_UNUSED(lineNumber)
+ XSDEBUG("FIXME: QmlEngine::executeJumpToLine()");
+}
+
+void QmlEngine::activateFrame(int index)
+{
+ Q_UNUSED(index)
+}
+
+void QmlEngine::selectThread(int index)
+{
+ Q_UNUSED(index)
+}
+
+void QmlEngine::attemptBreakpointSynchronization()
+{
+}
+
+void QmlEngine::loadSymbols(const QString &moduleName)
+{
+ Q_UNUSED(moduleName)
+}
+
+void QmlEngine::loadAllSymbols()
+{
+}
+
+void QmlEngine::reloadModules()
+{
+}
+
+void QmlEngine::requestModuleSymbols(const QString &moduleName)
+{
+ Q_UNUSED(moduleName)
+}
+
+
+void QmlEngine::handleResponse(const QByteArray &response)
+{
+ Q_UNUSED(response);
+/*
+ static QTime lastTime;
+
+ //showMessage(_(" "), currentTime(), LogTime);
+ QList<QByteArray> parts = response.split('\0');
+ if (parts.size() < 2 || !parts.last().isEmpty()) {
+ SDEBUG("WRONG RESPONSE PACKET LAYOUT" << parts);
+ //if (response.isEmpty())
+ acknowledgeResult();
+ return;
+ }
+ parts.removeLast(); // always empty
+ QByteArray tag = parts.at(0);
+ int n = parts.size();
+ if (n == 2 && tag == "N") { // unidentified command
+ int token = parts.at(1).toInt();
+ QmlCommand tcf = m_cookieForToken[token];
+ SDEBUG("COMMAND NOT RECOGNIZED FOR TOKEN" << token << tcf.toString());
+ showDebuggerOutput(LogOutput, QString::number(token) + "^"
+ + "NOT RECOQNIZED: " + quoteUnprintableLatin1(response));
+ acknowledgeResult();
+ } else if (n == 2 && tag == "F") { // flow control
+ m_congestion = parts.at(1).toInt();
+ SDEBUG("CONGESTION: " << m_congestion);
+ } else if (n == 4 && tag == "R") { // result data
+ acknowledgeResult();
+ int token = parts.at(1).toInt();
+ QByteArray message = parts.at(2);
+ QmlResponse data(parts.at(3));
+ showDebuggerOutput(LogOutput, QString("%1^%2%3").arg(token)
+ .arg(quoteUnprintableLatin1(response))
+ .arg(QString::fromUtf8(data.toString())));
+ QmlCommand tcf = m_cookieForToken[token];
+ QmlResponse result(data);
+ SDEBUG("GOOD RESPONSE: " << quoteUnprintableLatin1(response));
+ if (tcf.callback)
+ (this->*(tcf.callback))(result, tcf.cookie);
+ } else if (n == 3 && tag == "P") { // progress data (partial result)
+ //int token = parts.at(1).toInt();
+ QByteArray data = parts.at(2);
+ SDEBUG(_("\nTCF PARTIAL:") << quoteUnprintableLatin1(response));
+ } else if (n == 4 && tag == "E") { // an event
+ QByteArray service = parts.at(1);
+ QByteArray eventName = parts.at(2);
+ QmlResponse data(parts.at(3));
+ if (eventName != "peerHeartBeat")
+ SDEBUG(_("\nTCF EVENT:") << quoteUnprintableLatin1(response)
+ << data.toString());
+ if (service == "Locator" && eventName == "Hello") {
+ m_services.clear();
+ foreach (const QmlResponse &service, data.children())
+ m_services.append(service.data());
+ QTimer::singleShot(0, this, SLOT(startDebugging()));
+ }
+ } else {
+ SDEBUG("UNKNOWN RESPONSE PACKET:"
+ << quoteUnprintableLatin1(response) << parts);
+ }
+*/
+}
+
+void QmlEngine::startDebugging()
+{
+ qDebug() << "START";
+}
+
+void QmlEngine::postCommand(const QByteArray &cmd,
+ QmlCommandCallback callback, const char *callbackName)
+{
+ Q_UNUSED(cmd);
+ Q_UNUSED(callback);
+ Q_UNUSED(callbackName);
+/*
+ static int token = 20;
+ ++token;
+
+ //const char marker_eom = -1;
+ //const char marker_eos = -2;
+ //const char marker_null = -3;
+
+ QByteArray ba = "C";
+ ba.append('\0');
+ ba.append(QByteArray::number(token));
+ ba.append('\0');
+ ba.append(cmd);
+ ba.append('\0');
+ ba.append('\3');
+ ba.append('\1');
+
+ QmlCommand tcf;
+ tcf.command = ba;
+ tcf.callback = callback;
+ tcf.callbackName = callbackName;
+ tcf.token = token;
+
+ m_cookieForToken[token] = tcf;
+
+ enqueueCommand(tcf);
+*/
+}
+
+// Congestion control does not seem to work that way. Basically it's
+// already too late when we get a flow control packet
+void QmlEngine::enqueueCommand(const QmlCommand &cmd)
+{
+ Q_UNUSED(cmd);
+/*
+#ifdef USE_CONGESTION_CONTROL
+ // congestion controled
+ if (m_congestion <= 0 && m_sendQueue.isEmpty()) {
+ //SDEBUG("DIRECT SEND" << cmd.toString());
+ sendCommandNow(cmd);
+ } else {
+ SDEBUG("QUEUE " << cmd.toString());
+ m_sendQueue.enqueue(cmd);
+ m_sendTimer.start();
+ }
+#else
+ // synchrounously
+ if (m_inAir == 0)
+ sendCommandNow(cmd);
+ else
+ m_sendQueue.enqueue(cmd);
+#endif
+*/
+}
+
+void QmlEngine::handleSendTimer()
+{
+/*
+ QTC_ASSERT(!m_sendQueue.isEmpty(), return);
+
+ if (m_congestion > 0) {
+ // not ready...
+ SDEBUG("WAITING FOR CONGESTION TO GO DOWN...");
+ m_sendTimer.start();
+ } else {
+ // go!
+ sendCommandNow(m_sendQueue.dequeue());
+ }
+*/
+}
+
+void QmlEngine::sendCommandNow(const QmlCommand &cmd)
+{
+ ++m_inAir;
+ int result = m_socket->write(cmd.command);
+ Q_UNUSED(result)
+ m_socket->flush();
+ showMessage(QString::number(cmd.token) + " " + cmd.toString(), LogInput);
+ SDEBUG("SEND " << cmd.toString()); //<< " " << QString::number(result));
+}
+
+void QmlEngine::acknowledgeResult()
+{
+#if !defined(USE_CONGESTION_CONTROL)
+ QTC_ASSERT(m_inAir == 1, /**/);
+ m_inAir = 0;
+ if (!m_sendQueue.isEmpty())
+ sendCommandNow(m_sendQueue.dequeue());
+#endif
+}
+
+void QmlEngine::handleRunControlSuspend(const QmlResponse &data, const QVariant &)
+{
+ SDEBUG("HANDLE RESULT" << data.toString());
+}
+
+void QmlEngine::handleRunControlGetChildren(const QmlResponse &data, const QVariant &)
+{
+ SDEBUG("HANDLE RUN CONTROL GET CHILDREN" << data.toString());
+}
+
+void QmlEngine::handleSysMonitorGetChildren(const QmlResponse &data, const QVariant &)
+{
+ SDEBUG("HANDLE RUN CONTROL GET CHILDREN" << data.toString());
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Tooltip specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+static WatchData m_toolTip;
+static QPoint m_toolTipPos;
+static QHash<QString, WatchData> m_toolTipCache;
+
+void QmlEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
+{
+ Q_UNUSED(mousePos)
+ Q_UNUSED(editor)
+ Q_UNUSED(cursorPos)
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Watch specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void QmlEngine::assignValueInDebugger(const QString &expression,
+ const QString &value)
+{
+ XSDEBUG("ASSIGNING: " << expression + '=' + value);
+ updateLocals();
+}
+
+void QmlEngine::updateLocals()
+{
+}
+
+void QmlEngine::updateWatchData(const WatchData &)
+{
+ //qq->watchHandler()->rebuildModel();
+ showStatusMessage(tr("Stopped."), 5000);
+}
+
+void QmlEngine::updateSubItem(const WatchData &data0)
+{
+ Q_UNUSED(data0)
+ QTC_ASSERT(false, return);
+}
+
+IDebuggerEngine *createQmlEngine(DebuggerManager *manager)
+{
+ return new QmlEngine(manager);
+}
+
+} // namespace Internal
+} // namespace Debugger
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DEBUGGER_QMLENGINE_H
+#define DEBUGGER_QMLENGINE_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QHash>
+#include <QtCore/QMap>
+#include <QtCore/QObject>
+#include <QtCore/QPoint>
+#include <QtCore/QProcess>
+#include <QtCore/QQueue>
+#include <QtCore/QSet>
+#include <QtCore/QTimer>
+#include <QtCore/QVariant>
+
+#include <QtNetwork/QAbstractSocket>
+
+QT_BEGIN_NAMESPACE
+class QTcpSocket;
+QT_END_NAMESPACE
+
+#include "idebuggerengine.h"
+#include "debuggermanager.h"
+
+namespace Debugger {
+namespace Internal {
+
+class ScriptAgent;
+class WatchData;
+class QmlResponse;
+
+class QmlEngine : public IDebuggerEngine
+{
+ Q_OBJECT
+
+public:
+ explicit QmlEngine(DebuggerManager *parent);
+ ~QmlEngine();
+
+private:
+ // IDebuggerEngine implementation
+ void executeStep();
+ void executeStepOut();
+ void executeNext();
+ void executeStepI();
+ void executeNextI();
+
+ void shutdown();
+ void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos);
+ void startDebugger();
+ void exitDebugger();
+
+ void continueInferior();
+ Q_SLOT void runInferior();
+ void interruptInferior();
+
+ void executeRunToLine(const QString &fileName, int lineNumber);
+ void executeRunToFunction(const QString &functionName);
+ void executeJumpToLine(const QString &fileName, int lineNumber);
+
+ void activateFrame(int index);
+ void selectThread(int index);
+
+ void attemptBreakpointSynchronization();
+
+ void assignValueInDebugger(const QString &expr, const QString &value);
+ void executeDebuggerCommand(const QString & command);
+
+ void loadSymbols(const QString &moduleName);
+ void loadAllSymbols();
+ void requestModuleSymbols(const QString &moduleName);
+ void reloadModules();
+ void reloadRegisters() {}
+ void reloadSourceFiles() {}
+ void reloadFullStack() {}
+
+ bool supportsThreads() const { return true; }
+ void maybeBreakNow(bool byFunction);
+ void updateWatchData(const WatchData &data);
+ void updateLocals();
+ void updateSubItem(const WatchData &data);
+
+ Q_SLOT void socketConnected();
+ Q_SLOT void socketDisconnected();
+ Q_SLOT void socketError(QAbstractSocket::SocketError);
+ Q_SLOT void socketReadyRead();
+
+ void handleResponse(const QByteArray &ba);
+ void handleRunControlSuspend(const QmlResponse &response, const QVariant &);
+ void handleRunControlGetChildren(const QmlResponse &response, const QVariant &);
+ void handleSysMonitorGetChildren(const QmlResponse &response, const QVariant &);
+
+private:
+ Q_SLOT void startDebugging();
+
+ typedef void (QmlEngine::*QmlCommandCallback)
+ (const QmlResponse &record, const QVariant &cookie);
+
+ struct QmlCommand
+ {
+ QmlCommand() : flags(0), token(-1), callback(0), callbackName(0) {}
+
+ QString toString() const;
+
+ int flags;
+ int token;
+ QmlCommandCallback callback;
+ const char *callbackName;
+ QByteArray command;
+ QVariant cookie;
+ };
+
+ void postCommand(const QByteArray &cmd,
+ QmlCommandCallback callback = 0, const char *callbackName = 0);
+ void sendCommandNow(const QmlCommand &command);
+
+ QHash<int, QmlCommand> m_cookieForToken;
+
+ QQueue<QmlCommand> m_sendQueue;
+
+ // timer based congestion control. does not seem to work well.
+ void enqueueCommand(const QmlCommand &command);
+ Q_SLOT void handleSendTimer();
+ int m_congestion;
+ QTimer m_sendTimer;
+
+ // synchrounous communication
+ void acknowledgeResult();
+ int m_inAir;
+
+ QTcpSocket *m_socket;
+ QByteArray m_inbuffer;
+ QList<QByteArray> m_services;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_QMLENGINE_H
static const ItemFlags notEditable =
ItemIsSelectable
- | ItemIsDragEnabled
- | ItemIsDropEnabled
+ // | ItemIsDragEnabled
+ // | ItemIsDropEnabled
| ItemIsEnabled;
static const ItemFlags editable = notEditable | ItemIsEditable;
const QString msg = QString::fromLatin1("An exception was caught on %1: '%2'").
arg(scriptId).arg(exception.toString());
SDEBUG(msg);
- q->showDebuggerOutput(LogMisc, msg);
+ q->showMessage(msg, LogMisc);
}
void ScriptAgent::exceptionThrow(qint64 scriptId, const QScriptValue &exception,
const QString msg = QString::fromLatin1("An exception occurred on %1: '%2'").
arg(scriptId).arg(exception.toString());
SDEBUG(msg);
- q->showDebuggerOutput(LogMisc, msg);
+ q->showMessage(msg, LogMisc);
}
void ScriptAgent::functionEntry(qint64 scriptId)
{
Q_UNUSED(scriptId)
- q->showDebuggerOutput(LogMisc, QString::fromLatin1("Function entry occurred on %1").arg(scriptId));
+ q->showMessage(QString::fromLatin1("Function entry occurred on %1").arg(scriptId), LogMisc);
q->checkForBreakCondition(true);
}
Q_UNUSED(returnValue)
const QString msg = QString::fromLatin1("Function exit occurred on %1: '%2'").arg(scriptId).arg(returnValue.toString());
SDEBUG(msg);
- q->showDebuggerOutput(LogMisc, msg);
+ q->showMessage(msg, LogMisc);
}
void ScriptAgent::positionChange(qint64 scriptId, int lineNumber, int columnNumber)
Q_UNUSED(program)
Q_UNUSED(fileName)
Q_UNUSED(baseLineNumber)
- q->showDebuggerOutput(LogMisc, QString::fromLatin1("Loaded: %1 id: %2").arg(fileName).arg(scriptId));
+ q->showMessage(QString::fromLatin1("Loaded: %1 id: %2")
+ .arg(fileName).arg(scriptId), LogMisc);
}
void ScriptAgent::scriptUnload(qint64 scriptId)
setState(DebuggerNotReady);
}
-void ScriptEngine::startDebugger(const DebuggerStartParametersPtr &sp)
+void ScriptEngine::startDebugger()
{
setState(AdapterStarting);
if (m_scriptEngine.isNull())
setState(AdapterStarted);
setState(InferiorStarting);
- m_scriptFileName = QFileInfo (sp->executable).absoluteFilePath();
+ QTC_ASSERT(runControl(), return);
+ m_scriptFileName = QFileInfo(runControl()->sp().executable).absoluteFilePath();
QFile scriptFile(m_scriptFileName);
if (!scriptFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
- manager()->showDebuggerOutput(LogError, QString::fromLatin1("Cannot open %1: %2").
- arg(m_scriptFileName, scriptFile.errorString()));
+ showMessage(QString::fromLatin1("Cannot open %1: %2").
+ arg(m_scriptFileName, scriptFile.errorString()), LogError);
emit startFailed();
return;
}
attemptBreakpointSynchronization();
setState(InferiorRunningRequested);
showStatusMessage(tr("Running requested..."), 5000);
- manager()->showDebuggerOutput(LogMisc, QLatin1String("Running: ") + m_scriptFileName);
+ showMessage(QLatin1String("Running: ") + m_scriptFileName, LogMisc);
QTimer::singleShot(0, this, SLOT(runInferior()));
emit startSuccessful();
}
const QScriptValue result = m_scriptEngine->evaluate(m_scriptContents, m_scriptFileName);
setState(InferiorStopping);
setState(InferiorStopped);
+ QString msg;
if (m_scriptEngine->hasUncaughtException()) {
- QString msg = QString::fromLatin1("An exception occurred during execution at line: %1\n%2\n").
- arg(m_scriptEngine->uncaughtExceptionLineNumber()).arg(m_scriptEngine->uncaughtException().toString());
- msg += m_scriptEngine->uncaughtExceptionBacktrace().join(QString(QLatin1Char('\n')));
- showDebuggerOutput(LogMisc, msg);
+ msg = QString::fromLatin1("An exception occurred during execution at line: %1\n%2\n")
+ .arg(m_scriptEngine->uncaughtExceptionLineNumber())
+ .arg(m_scriptEngine->uncaughtException().toString());
+ msg += m_scriptEngine->uncaughtExceptionBacktrace()
+ .join(QString(QLatin1Char('\n')));
} else {
- showDebuggerOutput(LogMisc, QString::fromLatin1("Evaluation returns '%1'").arg(result.toString()));
+ msg = QString::fromLatin1("Evaluation returns '%1'")
+ .arg(result.toString());
}
+ showMessage(msg, LogMisc);
exitDebugger();
}
{
}
-QList<Symbol> ScriptEngine::moduleSymbols(const QString & /*moduleName*/)
+void ScriptEngine::requestModuleSymbols(const QString & /*moduleName*/)
{
- return QList<Symbol>();
}
manager()->watchHandler()->insertBulkData(children);
}
-void ScriptEngine::showDebuggerOutput(int channel, const QString &m)
-{
- manager()->showDebuggerOutput(channel, m);
-}
-
IDebuggerEngine *createScriptEngine(DebuggerManager *manager)
{
return new ScriptEngine(manager);
void shutdown();
void setToolTipExpression(const QPoint &mousePos,
TextEditor::ITextEditor *editor, int cursorPos);
- void startDebugger(const DebuggerStartParametersPtr &sp);
-
+ void startDebugger();
void exitDebugger();
void continueInferior();
void attemptBreakpointSynchronization();
void assignValueInDebugger(const QString &expr, const QString &value);
- void executeDebuggerCommand(const QString & command);
+ void executeDebuggerCommand(const QString &command);
void loadSymbols(const QString &moduleName);
void loadAllSymbols();
- virtual QList<Symbol> moduleSymbols(const QString &moduleName);
+ void requestModuleSymbols(const QString &moduleName);
void reloadModules();
void reloadRegisters() {}
void reloadSourceFiles() {}
void updateLocals();
void updateSubItem(const WatchData &data);
- Q_SLOT void showDebuggerOutput(int channel, const QString &m);
-
private:
friend class ScriptAgent;
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "stackframe.h"
+#include "stackhandler.h"
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+
+namespace Debugger {
+namespace Internal {
+
+////////////////////////////////////////////////////////////////////////
+//
+// StackFrame
+//
+////////////////////////////////////////////////////////////////////////
+
+StackFrame::StackFrame()
+ : level(0), line(0)
+{}
+
+void StackFrame::clear()
+{
+ line = level = 0;
+ function.clear();
+ file.clear();
+ from.clear();
+ to.clear();
+ address.clear();
+}
+
+bool StackFrame::isUsable() const
+{
+ return !file.isEmpty() && QFileInfo(file).isReadable();
+}
+
+QString StackFrame::toString() const
+{
+ QString res;
+ QTextStream str(&res);
+ str << StackHandler::tr("Address:") << ' ' << address << ' '
+ << StackHandler::tr("Function:") << ' ' << function << ' '
+ << StackHandler::tr("File:") << ' ' << file << ' '
+ << StackHandler::tr("Line:") << ' ' << line << ' '
+ << StackHandler::tr("From:") << ' ' << from << ' '
+ << StackHandler::tr("To:") << ' ' << to;
+ return res;
+}
+
+QString StackFrame::toToolTip() const
+{
+ QString res;
+ QTextStream str(&res);
+ str << "<html><body><table>"
+ << "<tr><td>" << StackHandler::tr("Address:") << "</td><td>" << address << "</td></tr>"
+ << "<tr><td>" << StackHandler::tr("Function:") << "</td><td>" << function << "</td></tr>"
+ << "<tr><td>" << StackHandler::tr("File:") << "</td><td>" << QDir::toNativeSeparators(file) << "</td></tr>"
+ << "<tr><td>" << StackHandler::tr("Line:") << "</td><td>" << line << "</td></tr>"
+ << "<tr><td>" << StackHandler::tr("From:") << "</td><td>" << from << "</td></tr>"
+ << "<tr><td>" << StackHandler::tr("To:") << "</td><td>" << to << "</td></tr>"
+ << "</table></body></html>";
+ return res;
+}
+
+QDebug operator<<(QDebug d, const StackFrame &f)
+{
+ QString res;
+ QTextStream str(&res);
+ str << "level=" << f.level << " address=" << f.address;
+ if (!f.function.isEmpty())
+ str << ' ' << f.function;
+ if (!f.file.isEmpty())
+ str << ' ' << f.file << ':' << f.line;
+ if (!f.from.isEmpty())
+ str << " from=" << f.from;
+ if (!f.to.isEmpty())
+ str << " to=" << f.to;
+ d.nospace() << res;
+ return d;
+}
+
+} // namespace Internal
+} // namespace Debugger
namespace Debugger {
namespace Internal {
-StackFrame::StackFrame()
- : level(0), line(0)
-{}
-
-void StackFrame::clear()
-{
- line = level = 0;
- function.clear();
- file.clear();
- from.clear();
- to.clear();
- address.clear();
-}
-
-bool StackFrame::isUsable() const
-{
- return !file.isEmpty() && QFileInfo(file).isReadable();
-}
-
-QString StackFrame::toString() const
-{
- QString res;
- QTextStream str(&res);
- str << StackHandler::tr("Address:") << ' ' << address << ' '
- << StackHandler::tr("Function:") << ' ' << function << ' '
- << StackHandler::tr("File:") << ' ' << file << ' '
- << StackHandler::tr("Line:") << ' ' << line << ' '
- << StackHandler::tr("From:") << ' ' << from << ' '
- << StackHandler::tr("To:") << ' ' << to;
- return res;
-}
-
-QString StackFrame::toToolTip() const
-{
- QString res;
- QTextStream str(&res);
- str << "<html><body><table>"
- << "<tr><td>" << StackHandler::tr("Address:") << "</td><td>" << address << "</td></tr>"
- << "<tr><td>" << StackHandler::tr("Function:") << "</td><td>" << function << "</td></tr>"
- << "<tr><td>" << StackHandler::tr("File:") << "</td><td>" << QDir::toNativeSeparators(file) << "</td></tr>"
- << "<tr><td>" << StackHandler::tr("Line:") << "</td><td>" << line << "</td></tr>"
- << "<tr><td>" << StackHandler::tr("From:") << "</td><td>" << from << "</td></tr>"
- << "<tr><td>" << StackHandler::tr("To:") << "</td><td>" << to << "</td></tr>"
- << "</table></body></html>";
- return res;
-}
-
-QDebug operator<<(QDebug d, const StackFrame &f)
-{
- QString res;
- QTextStream str(&res);
- str << "level=" << f.level << " address=" << f.address;
- if (!f.function.isEmpty())
- str << ' ' << f.function;
- if (!f.file.isEmpty())
- str << ' ' << f.file << ':' << f.line;
- if (!f.from.isEmpty())
- str << " from=" << f.from;
- if (!f.to.isEmpty())
- str << " to=" << f.to;
- d.nospace() << res;
- return d;
-}
////////////////////////////////////////////////////////////////////////
//
}
-////////////////////////////////////////////////////////////////////////
-//
-// ThreadsHandler
-//
-////////////////////////////////////////////////////////////////////////
-
-ThreadData::ThreadData(int threadId) :
- id(threadId),
- address(0),
- line(-1)
-{
-}
-
-void ThreadData::notifyRunning()
-{
- address = 0;
- function.clear();
- file.clear();
- line = -1;
-}
-
-enum { IdColumn, AddressColumn, FunctionColumn, FileColumn, LineColumn, ColumnCount };
-
-ThreadsHandler::ThreadsHandler(QObject *parent) :
- QAbstractTableModel(parent),
- m_currentIndex(0),
- m_positionIcon(QLatin1String(":/debugger/images/location_16.png")),
- m_emptyIcon(QLatin1String(":/debugger/images/debugger_empty_14.png"))
-{
-}
-
-int ThreadsHandler::rowCount(const QModelIndex &parent) const
-{
- // Since the stack is not a tree, row count is 0 for any valid parent
- return parent.isValid() ? 0 : m_threads.size();
-}
-
-int ThreadsHandler::columnCount(const QModelIndex &parent) const
-{
- return parent.isValid() ? 0 : int(ColumnCount);
-}
-
-QVariant ThreadsHandler::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid())
- return QVariant();
- const int row = index.row();
- if (row >= m_threads.size())
- return QVariant();
- const ThreadData &thread = m_threads.at(row);
-
- if (role == Qt::DisplayRole) {
- switch (index.column()) {
- case IdColumn:
- return thread.id;
- case FunctionColumn:
- return thread.function;
- case FileColumn:
- return thread.file;
- case LineColumn:
- return thread.line >= 0 ? QString::number(thread.line) : QString();
- case AddressColumn:
- return thread.address > 0 ? QLatin1String("0x") + QString::number(thread.address, 16) : QString();
- }
- } else if (role == Qt::ToolTipRole) {
- if (thread.address == 0)
- return tr("Thread: %1").arg(thread.id);
- // Stopped
- if (thread.file.isEmpty())
- return tr("Thread: %1 at %2 (0x%3)").arg(thread.id).arg(thread.function).arg(thread.address, 0, 16);
- return tr("Thread: %1 at %2, %3:%4 (0x%5)").
- arg(thread.id).arg(thread.function, thread.file).arg(thread.line).arg(thread.address, 0, 16);
- } else if (role == Qt::DecorationRole && index.column() == 0) {
- // Return icon that indicates whether this is the active stack frame
- return (index.row() == m_currentIndex) ? m_positionIcon : m_emptyIcon;
- }
-
- return QVariant();
-}
-
-QVariant ThreadsHandler::headerData(int section, Qt::Orientation orientation, int role) const
-{
- if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
- return QVariant();
- switch (section) {
- case IdColumn:
- return tr("Thread ID");
- case FunctionColumn:
- return tr("Function");
- case FileColumn:
- return tr("File");
- case LineColumn:
- return tr("Line");
- case AddressColumn:
- return tr("Address");
- }
- return QVariant();
-}
-
-void ThreadsHandler::setCurrentThread(int index)
-{
- if (index == m_currentIndex)
- return;
-
- // Emit changed for previous frame
- QModelIndex i = ThreadsHandler::index(m_currentIndex, 0);
- emit dataChanged(i, i);
-
- m_currentIndex = index;
-
- // Emit changed for new frame
- i = ThreadsHandler::index(m_currentIndex, 0);
- emit dataChanged(i, i);
-}
-
-void ThreadsHandler::setThreads(const QList<ThreadData> &threads)
-{
- m_threads = threads;
- if (m_currentIndex >= m_threads.size())
- m_currentIndex = m_threads.size() - 1;
- reset();
-}
-
-QList<ThreadData> ThreadsHandler::threads() const
-{
- return m_threads;
-}
-
-void ThreadsHandler::removeAll()
-{
- m_threads.clear();
- m_currentIndex = 0;
- reset();
-}
-
-void ThreadsHandler::notifyRunning()
-{
- // Threads stopped (that is, address != 0 showing)?
- if (m_threads.empty())
- return;
- if (m_threads.front().address == 0)
- return;
- const QList<ThreadData>::iterator end = m_threads.end();
- for (QList<ThreadData>::iterator it = m_threads.begin(); it != end; ++it)
- it->notifyRunning();
- emit dataChanged(index(0, 1), index(m_threads.size()- 1, ColumnCount - 1));
-}
-
} // namespace Internal
} // namespace Debugger
namespace Debugger {
namespace Internal {
+////////////////////////////////////////////////////////////////////////
+//
+// StackModel
+//
+////////////////////////////////////////////////////////////////////////
+
struct StackCookie
{
StackCookie() : isFull(true), gotoLocation(false) {}
};
-////////////////////////////////////////////////////////////////////////
-//
-// ThreadsHandler
-//
-////////////////////////////////////////////////////////////////////////
-
-struct ThreadData
-{
- ThreadData(int threadId = 0);
- void notifyRunning(); // Clear state information
-
- int id;
- // State information when stopped
- quint64 address;
- QString function;
- QString file;
- int line;
-};
-
-/*! A model to represent the running threads in a QTreeView or ComboBox */
-class ThreadsHandler : public QAbstractTableModel
-{
- Q_OBJECT
-
-public:
- ThreadsHandler(QObject *parent = 0);
-
- void setCurrentThread(int index);
- void selectThread(int index);
- void setThreads(const QList<ThreadData> &threads);
- void removeAll();
- QList<ThreadData> threads() const;
- QAbstractItemModel *threadsModel() { return this; }
-
- // Clear out all frame information
- void notifyRunning();
-
-private:
- int rowCount(const QModelIndex &parent = QModelIndex()) const;
- int columnCount(const QModelIndex &parent = QModelIndex()) const;
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
- QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
-
-private:
- QList<ThreadData> m_threads;
- int m_currentIndex;
- const QIcon m_positionIcon;
- const QIcon m_emptyIcon;
-};
-
} // namespace Internal
} // namespace Debugger
str += '\n';
}
QClipboard *clipboard = QApplication::clipboard();
- #ifdef Q_WS_X11
+# ifdef Q_WS_X11
clipboard->setText(str, QClipboard::Selection);
- #endif
+# endif
clipboard->setText(str, QClipboard::Clipboard);
}
</property>
</widget>
</item>
+ <item row="0" column="1">
+ <widget class="Utils::PathChooser" name="execFile" native="true"/>
+ </item>
<item row="1" column="0">
<widget class="QLabel" name="argLabel">
<property name="text">
<item row="1" column="1">
<widget class="QLineEdit" name="argsEdit"/>
</item>
- <item row="0" column="1">
- <widget class="Utils::PathChooser" name="execFile" native="true"/>
+ <item row="2" column="0">
+ <widget class="QLabel" name="workingDirectoryLabel">
+ <property name="text">
+ <string>Working directory:</string>
+ </property>
+ </widget>
</item>
<item row="2" column="1">
+ <widget class="Utils::PathChooser" name="workingDirectory" native="true"/>
+ </item>
+ <item row="3" column="1">
<widget class="QCheckBox" name="checkBoxBreakAtMain">
<property name="text">
<string/>
</property>
</widget>
</item>
- <item row="2" column="0">
+ <item row="3" column="0">
<widget class="QLabel" name="labelBreakAtMain">
<property name="text">
<string>Break at 'main':</string>
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "json.h"
+
+#include <utils/qtcassert.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QTextStream>
+
+#include <ctype.h>
+
+//#define DEBUG_JASON
+#ifdef DEBUG_JASON
+#define JDEBUG(s) qDebug() << s
+#else
+#define JDEBUG(s)
+#endif
+
+namespace Debugger {
+namespace Internal {
+
+static void skipSpaces(const char *&from, const char *to)
+{
+ while (from != to && isspace(*from))
+ ++from;
+}
+
+QTextStream &operator<<(QTextStream &os, const JsonValue &mi)
+{
+ return os << mi.toString();
+}
+
+void JsonValue::parsePair(const char *&from, const char *to)
+{
+ skipSpaces(from, to);
+ JDEBUG("parsePair: " << QByteArray(from, to - from));
+ m_name = parseCString(from, to);
+ skipSpaces(from, to);
+ while (from < to && *from != ':') {
+ JDEBUG("not a colon" << *from);
+ ++from;
+ }
+ ++from;
+ parseValue(from, to);
+ skipSpaces(from, to);
+}
+
+QByteArray JsonValue::parseNumber(const char *&from, const char *to)
+{
+ QByteArray result;
+ while (from < to && *from >= '0' && *from <= '9')
+ result.append(*from++);
+ return result;
+}
+
+QByteArray JsonValue::parseCString(const char *&from, const char *to)
+{
+ QByteArray result;
+ JDEBUG("parseCString: " << QByteArray(from, to - from));
+ if (*from != '"') {
+ qDebug() << "JSON Parse Error, double quote expected";
+ ++from; // So we don't hang
+ return QByteArray();
+ }
+ const char *ptr = from;
+ ++ptr;
+ while (ptr < to) {
+ if (*ptr == '"') {
+ ++ptr;
+ result = QByteArray(from + 1, ptr - from - 2);
+ break;
+ }
+ if (*ptr == '\\') {
+ ++ptr;
+ if (ptr == to) {
+ qDebug() << "JSON Parse Error, unterminated backslash escape";
+ from = ptr; // So we don't hang
+ return QByteArray();
+ }
+ }
+ ++ptr;
+ }
+ from = ptr;
+
+ int idx = result.indexOf('\\');
+ if (idx >= 0) {
+ char *dst = result.data() + idx;
+ const char *src = dst + 1, *end = result.data() + result.length();
+ do {
+ char c = *src++;
+ switch (c) {
+ case 'a': *dst++ = '\a'; break;
+ case 'b': *dst++ = '\b'; break;
+ case 'f': *dst++ = '\f'; break;
+ case 'n': *dst++ = '\n'; break;
+ case 'r': *dst++ = '\r'; break;
+ case 't': *dst++ = '\t'; break;
+ case 'v': *dst++ = '\v'; break;
+ case '"': *dst++ = '"'; break;
+ case '\\': *dst++ = '\\'; break;
+ default:
+ {
+ int chars = 0;
+ uchar prod = 0;
+ forever {
+ if (c < '0' || c > '7') {
+ --src;
+ break;
+ }
+ prod = prod * 8 + c - '0';
+ if (++chars == 3 || src == end)
+ break;
+ c = *src++;
+ }
+ if (!chars) {
+ qDebug() << "JSON Parse Error, unrecognized backslash escape";
+ return QByteArray();
+ }
+ *dst++ = prod;
+ }
+ }
+ while (src != end) {
+ char c = *src++;
+ if (c == '\\')
+ break;
+ *dst++ = c;
+ }
+ } while (src != end);
+ *dst = 0;
+ result.truncate(dst - result.data());
+ }
+
+ JDEBUG("parseCString, got " << result);
+ return result;
+}
+
+void JsonValue::parseValue(const char *&from, const char *to)
+{
+ JDEBUG("parseValue: " << QByteArray(from, to - from));
+ switch (*from) {
+ case '{':
+ parseObject(from, to);
+ break;
+ case '[':
+ parseArray(from, to);
+ break;
+ case '"':
+ m_type = String;
+ m_data = parseCString(from, to);
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ m_type = Number;
+ m_data = parseNumber(from, to);
+ default:
+ break;
+ }
+}
+
+void JsonValue::parseObject(const char *&from, const char *to)
+{
+ JDEBUG("parseObject: " << QByteArray(from, to - from));
+ QTC_ASSERT(*from == '{', /**/);
+ ++from;
+ m_type = Object;
+ while (from < to) {
+ if (*from == '}') {
+ ++from;
+ break;
+ }
+ JsonValue child;
+ child.parsePair(from, to);
+ if (!child.isValid())
+ return;
+ m_children += child;
+ if (*from == ',')
+ ++from;
+ }
+}
+
+void JsonValue::parseArray(const char *&from, const char *to)
+{
+ JDEBUG("parseArray: " << QByteArray(from, to - from));
+ QTC_ASSERT(*from == '[', /**/);
+ ++from;
+ m_type = Array;
+ while (from < to) {
+ if (*from == ']') {
+ ++from;
+ break;
+ }
+ JsonValue child;
+ child.parseValue(from, to);
+ if (child.isValid())
+ m_children += child;
+ if (*from == ',')
+ ++from;
+ }
+}
+
+void JsonValue::setStreamOutput(const QByteArray &name, const QByteArray &content)
+{
+ if (content.isEmpty())
+ return;
+ JsonValue child;
+ child.m_type = String;
+ child.m_name = name;
+ child.m_data = content;
+ m_children += child;
+ if (m_type == Invalid)
+ m_type = Object;
+}
+
+static QByteArray ind(int indent)
+{
+ return QByteArray(2 * indent, ' ');
+}
+
+void JsonValue::dumpChildren(QByteArray * str, bool multiline, int indent) const
+{
+ for (int i = 0; i < m_children.size(); ++i) {
+ if (i != 0) {
+ *str += ',';
+ if (multiline)
+ *str += '\n';
+ }
+ if (multiline)
+ *str += ind(indent);
+ *str += m_children.at(i).toString(multiline, indent);
+ }
+}
+
+class MyString : public QString {
+public:
+ ushort at(int i) const { return constData()[i].unicode(); }
+};
+
+template<class ST, typename CT>
+inline ST escapeCStringTpl(const ST &ba)
+{
+ ST ret;
+ ret.reserve(ba.length() * 2);
+ for (int i = 0; i < ba.length(); ++i) {
+ CT c = ba.at(i);
+ switch (c) {
+ case '\\': ret += "\\\\"; break;
+ case '\a': ret += "\\a"; break;
+ case '\b': ret += "\\b"; break;
+ case '\f': ret += "\\f"; break;
+ case '\n': ret += "\\n"; break;
+ case '\r': ret += "\\r"; break;
+ case '\t': ret += "\\t"; break;
+ case '\v': ret += "\\v"; break;
+ case '"': ret += "\\\""; break;
+ default:
+ if (c < 32 || c == 127) {
+ ret += '\\';
+ ret += '0' + (c >> 6);
+ ret += '0' + ((c >> 3) & 7);
+ ret += '0' + (c & 7);
+ } else {
+ ret += c;
+ }
+ }
+ }
+ return ret;
+}
+
+QString JsonValue::escapeCString(const QString &ba)
+{
+ return escapeCStringTpl<MyString, ushort>(static_cast<const MyString &>(ba));
+}
+
+QByteArray JsonValue::escapeCString(const QByteArray &ba)
+{
+ return escapeCStringTpl<QByteArray, uchar>(ba);
+}
+
+QByteArray JsonValue::toString(bool multiline, int indent) const
+{
+ QByteArray result;
+ switch (m_type) {
+ case Invalid:
+ if (multiline)
+ result += ind(indent) + "Invalid\n";
+ else
+ result += "Invalid";
+ break;
+ case String:
+ if (!m_name.isEmpty())
+ result += m_name + "=";
+ result += '"' + escapeCString(m_data) + '"';
+ break;
+ case Number:
+ if (!m_name.isEmpty())
+ result += '"' + m_name + "\":";
+ result += m_data;
+ break;
+ case Object:
+ if (!m_name.isEmpty())
+ result += m_name + '=';
+ if (multiline) {
+ result += "{\n";
+ dumpChildren(&result, multiline, indent + 1);
+ result += '\n' + ind(indent) + "}";
+ } else {
+ result += "{";
+ dumpChildren(&result, multiline, indent + 1);
+ result += "}";
+ }
+ break;
+ case Array:
+ if (!m_name.isEmpty())
+ result += m_name + "=";
+ if (multiline) {
+ result += "[\n";
+ dumpChildren(&result, multiline, indent + 1);
+ result += '\n' + ind(indent) + "]";
+ } else {
+ result += "[";
+ dumpChildren(&result, multiline, indent + 1);
+ result += "]";
+ }
+ break;
+ }
+ return result;
+}
+
+void JsonValue::fromString(const QByteArray &ba)
+{
+ const char *from = ba.constBegin();
+ const char *to = ba.constEnd();
+ parseValue(from, to);
+}
+
+JsonValue JsonValue::findChild(const char *name) const
+{
+ for (int i = 0; i < m_children.size(); ++i)
+ if (m_children.at(i).m_name == name)
+ return m_children.at(i);
+ return JsonValue();
+}
+
+} // namespace Internal
+} // namespace Debugger
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DEBUGGER_JSON_H
+#define DEBUGGER_JSON_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+
+namespace Debugger {
+namespace Internal {
+
+class JsonValue
+{
+public:
+ JsonValue() : m_type(Invalid) {}
+ explicit JsonValue(const QByteArray &str) { fromString(str); }
+
+ QByteArray m_name;
+ QByteArray m_data;
+ QList<JsonValue> m_children;
+
+ enum Type {
+ Invalid,
+ String,
+ Number,
+ Object,
+ Array,
+ };
+
+ Type m_type;
+
+ inline Type type() const { return m_type; }
+ inline QByteArray name() const { return m_name; }
+ inline bool hasName(const char *name) const { return m_name == name; }
+
+ inline bool isValid() const { return m_type != Invalid; }
+ inline bool isNumber() const { return m_type == Number; }
+ inline bool isString() const { return m_type == String; }
+ inline bool isObject() const { return m_type == Object; }
+ inline bool isArray() const { return m_type == Array; }
+
+
+ inline QByteArray data() const { return m_data; }
+ inline const QList<JsonValue> &children() const { return m_children; }
+ inline int childCount() const { return m_children.size(); }
+
+ const JsonValue &childAt(int index) const { return m_children[index]; }
+ JsonValue &childAt(int index) { return m_children[index]; }
+ JsonValue findChild(const char *name) const;
+
+ QByteArray toString(bool multiline = false, int indent = 0) const;
+ void fromString(const QByteArray &str);
+ void setStreamOutput(const QByteArray &name, const QByteArray &content);
+
+private:
+ static QByteArray parseCString(const char *&from, const char *to);
+ static QByteArray parseNumber(const char *&from, const char *to);
+ static QByteArray escapeCString(const QByteArray &ba);
+ static QString escapeCString(const QString &ba);
+ void parsePair(const char *&from, const char *to);
+ void parseValue(const char *&from, const char *to);
+ void parseObject(const char *&from, const char *to);
+ void parseArray(const char *&from, const char *to);
+
+ void dumpChildren(QByteArray *str, bool multiline, int indent) const;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+//Q_DECLARE_METATYPE(GdbDebugger::Internal::JsonValue);
+
+#endif // DEBUGGER_JSON_H
--- /dev/null
+HEADERS += \
+ $$PWD/json.h \
+ $$PWD/tcfengine.h \
+
+SOURCES += \
+ $$PWD/json.cpp \
+ $$PWD/tcfengine.cpp \
+
+FORMS +=
+
+RESOURCES +=
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "tcfengine.h"
+
+#include "debuggerstringutils.h"
+#include "debuggerdialogs.h"
+#include "breakhandler.h"
+#include "debuggerconstants.h"
+#include "debuggermanager.h"
+#include "moduleshandler.h"
+#include "registerhandler.h"
+#include "stackhandler.h"
+#include "watchhandler.h"
+#include "watchutils.h"
+#include "moduleshandler.h"
+#include "json.h"
+
+#include <utils/qtcassert.h>
+
+#include <QtCore/QDateTime>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTimer>
+
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QMainWindow>
+#include <QtGui/QMessageBox>
+#include <QtGui/QToolTip>
+
+#include <QtNetwork/QTcpSocket>
+
+#define DEBUG_TCF 1
+#if DEBUG_TCF
+# define SDEBUG(s) qDebug() << s
+#else
+# define SDEBUG(s)
+#endif
+# define XSDEBUG(s) qDebug() << s
+
+#define CB(callback) &TcfEngine::callback, STRINGIFY(callback)
+
+//#define USE_CONGESTION_CONTROL
+
+static QByteArray C(const QByteArray &ba1,
+ const QByteArray &ba2 = QByteArray(),
+ const QByteArray &ba3 = QByteArray(),
+ const QByteArray &ba4 = QByteArray(),
+ const QByteArray &ba5 = QByteArray())
+{
+ QByteArray result = ba1;
+ if (!ba2.isEmpty()) { result += '\0'; result += ba2; }
+ if (!ba3.isEmpty()) { result += '\0'; result += ba3; }
+ if (!ba4.isEmpty()) { result += '\0'; result += ba4; }
+ if (!ba5.isEmpty()) { result += '\0'; result += ba5; }
+ return result;
+}
+
+namespace Debugger {
+namespace Internal {
+
+///////////////////////////////////////////////////////////////////////
+//
+// TcfCommand
+//
+///////////////////////////////////////////////////////////////////////
+
+
+QString TcfEngine::TcfCommand::toString() const
+{
+ return quoteUnprintableLatin1(command);
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// TcfEngine
+//
+///////////////////////////////////////////////////////////////////////
+
+TcfEngine::TcfEngine(DebuggerManager *manager)
+ : IDebuggerEngine(manager)
+{
+ m_congestion = 0;
+ m_inAir = 0;
+
+ m_sendTimer.setSingleShot(true);
+ m_sendTimer.setInterval(100); // ms
+ connect(&m_sendTimer, SIGNAL(timeout()), this, SLOT(handleSendTimer()));
+
+ m_socket = new QTcpSocket(this);
+ connect(m_socket, SIGNAL(connected()), this, SLOT(socketConnected()));
+ connect(m_socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
+ connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ this, SLOT(socketError(QAbstractSocket::SocketError)));
+
+ //void aboutToClose ()
+ //void bytesWritten ( qint64 bytes )
+ //void readChannelFinished ()
+ connect(m_socket, SIGNAL(readyRead()), this, SLOT(socketReadyRead()));
+
+ //connect(m_socket, SIGNAL(hostFound())
+ //connect(m_socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy, QAuthenticator *)))
+ //connect(m_socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ // thism SLOT(socketStateChanged(QAbstractSocket::SocketState)));
+}
+
+TcfEngine::~TcfEngine()
+{
+}
+
+void TcfEngine::socketReadyRead()
+{
+ //XSDEBUG("TcfEngine::socketReadyRead()");
+ m_inbuffer.append(m_socket->readAll());
+ int pos = 0;
+ while (1) {
+ // the "\3" is followed by either "\1" or "\2"
+ int next = m_inbuffer.indexOf("\3", pos);
+ //qDebug() << "pos: " << pos << "next: " << next;
+ if (next == -1)
+ break;
+ handleResponse(m_inbuffer.mid(pos, next - pos));
+ pos = next + 2;
+ }
+ m_inbuffer.clear();
+}
+
+void TcfEngine::socketConnected()
+{
+ showStatusMessage("Socket connected.");
+ m_socket->waitForConnected(2000);
+ //sendCommand("Locator", "redirect", "ID");
+}
+
+void TcfEngine::socketDisconnected()
+{
+ XSDEBUG("FIXME: TcfEngine::socketDisconnected()");
+}
+
+void TcfEngine::socketError(QAbstractSocket::SocketError)
+{
+ QString msg = tr("%1.").arg(m_socket->errorString());
+ //QMessageBox::critical(q->mainWindow(), tr("Error"), msg);
+ showStatusMessage(msg);
+ manager()->notifyInferiorExited();
+}
+
+void TcfEngine::executeDebuggerCommand(const QString &command)
+{
+ QByteArray cmd = command.toUtf8();
+ cmd = cmd.mid(cmd.indexOf(' ') + 1);
+ QByteArray null;
+ null.append('\0');
+ // FIXME: works for single-digit escapes only
+ cmd.replace("\\0", null);
+ cmd.replace("\\1", "\1");
+ cmd.replace("\\3", "\3");
+ TcfCommand tcf;
+ tcf.command = cmd;
+ enqueueCommand(tcf);
+}
+
+void TcfEngine::shutdown()
+{
+ m_congestion = 0;
+ m_inAir = 0;
+ m_services.clear();
+ exitDebugger();
+}
+
+void TcfEngine::exitDebugger()
+{
+ SDEBUG("TcfEngine::exitDebugger()");
+ manager()->notifyInferiorExited();
+}
+
+void TcfEngine::startDebugger()
+{
+ QTC_ASSERT(runControl(), return);
+ setState(InferiorRunningRequested);
+ showStatusMessage(tr("Running requested..."), 5000);
+ const DebuggerStartParameters &sp = runControl()->sp();
+ const int pos = sp.remoteChannel.indexOf(QLatin1Char(':'));
+ const QString host = sp.remoteChannel.left(pos);
+ const quint16 port = sp.remoteChannel.mid(pos + 1).toInt();
+ //QTimer::singleShot(0, this, SLOT(runInferior()));
+ m_socket->connectToHost(host, port);
+ emit startSuccessful();
+}
+
+void TcfEngine::continueInferior()
+{
+ SDEBUG("TcfEngine::continueInferior()");
+}
+
+void TcfEngine::runInferior()
+{
+}
+
+void TcfEngine::interruptInferior()
+{
+ XSDEBUG("TcfEngine::interruptInferior()");
+}
+
+void TcfEngine::executeStep()
+{
+ //SDEBUG("TcfEngine::executeStep()");
+}
+
+void TcfEngine::executeStepI()
+{
+ //SDEBUG("TcfEngine::executeStepI()");
+}
+
+void TcfEngine::executeStepOut()
+{
+ //SDEBUG("TcfEngine::executeStepOut()");
+}
+
+void TcfEngine::executeNext()
+{
+ //SDEBUG("TcfEngine::nextExec()");
+}
+
+void TcfEngine::executeNextI()
+{
+ //SDEBUG("TcfEngine::executeNextI()");
+}
+
+void TcfEngine::executeRunToLine(const QString &fileName, int lineNumber)
+{
+ Q_UNUSED(fileName)
+ Q_UNUSED(lineNumber)
+ SDEBUG("FIXME: TcfEngine::executeRunToLine()");
+}
+
+void TcfEngine::executeRunToFunction(const QString &functionName)
+{
+ Q_UNUSED(functionName)
+ XSDEBUG("FIXME: TcfEngine::executeRunToFunction()");
+}
+
+void TcfEngine::executeJumpToLine(const QString &fileName, int lineNumber)
+{
+ Q_UNUSED(fileName)
+ Q_UNUSED(lineNumber)
+ XSDEBUG("FIXME: TcfEngine::executeJumpToLine()");
+}
+
+void TcfEngine::activateFrame(int index)
+{
+ Q_UNUSED(index)
+}
+
+void TcfEngine::selectThread(int index)
+{
+ Q_UNUSED(index)
+}
+
+void TcfEngine::attemptBreakpointSynchronization()
+{
+}
+
+void TcfEngine::loadSymbols(const QString &moduleName)
+{
+ Q_UNUSED(moduleName)
+}
+
+void TcfEngine::loadAllSymbols()
+{
+}
+
+void TcfEngine::reloadModules()
+{
+}
+
+void TcfEngine::requestModuleSymbols(const QString &moduleName)
+{
+ Q_UNUSED(moduleName)
+}
+
+
+void TcfEngine::handleResponse(const QByteArray &response)
+{
+ static QTime lastTime;
+
+ //showMessage(_(" "), currentTime(), LogTime);
+ QList<QByteArray> parts = response.split('\0');
+ if (parts.size() < 2 || !parts.last().isEmpty()) {
+ SDEBUG("WRONG RESPONSE PACKET LAYOUT" << parts);
+ //if (response.isEmpty())
+ acknowledgeResult();
+ return;
+ }
+ parts.removeLast(); // always empty
+ QByteArray tag = parts.at(0);
+ int n = parts.size();
+ if (n == 2 && tag == "N") { // unidentified command
+ int token = parts.at(1).toInt();
+ TcfCommand tcf = m_cookieForToken[token];
+ SDEBUG("COMMAND NOT RECOGNIZED FOR TOKEN" << token << tcf.toString());
+ showMessage(QString::number(token) + "^"
+ + "NOT RECOQNIZED: " + quoteUnprintableLatin1(response),
+ LogOutput);
+ acknowledgeResult();
+ } else if (n == 2 && tag == "F") { // flow control
+ m_congestion = parts.at(1).toInt();
+ SDEBUG("CONGESTION: " << m_congestion);
+ } else if (n == 4 && tag == "R") { // result data
+ acknowledgeResult();
+ int token = parts.at(1).toInt();
+ QByteArray message = parts.at(2);
+ JsonValue data(parts.at(3));
+ showMessage(QString("%1^%2%3").arg(token)
+ .arg(quoteUnprintableLatin1(response))
+ .arg(QString::fromUtf8(data.toString())), LogOutput);
+ TcfCommand tcf = m_cookieForToken[token];
+ JsonValue result(data);
+ SDEBUG("GOOD RESPONSE: " << quoteUnprintableLatin1(response));
+ if (tcf.callback)
+ (this->*(tcf.callback))(result, tcf.cookie);
+ } else if (n == 3 && tag == "P") { // progress data (partial result)
+ //int token = parts.at(1).toInt();
+ QByteArray data = parts.at(2);
+ SDEBUG(_("\nTCF PARTIAL:") << quoteUnprintableLatin1(response));
+ } else if (n == 4 && tag == "E") { // an event
+ QByteArray service = parts.at(1);
+ QByteArray eventName = parts.at(2);
+ JsonValue data(parts.at(3));
+ if (eventName != "peerHeartBeat")
+ SDEBUG(_("\nTCF EVENT:") << quoteUnprintableLatin1(response)
+ << data.toString());
+ if (service == "Locator" && eventName == "Hello") {
+ m_services.clear();
+ foreach (const JsonValue &service, data.children())
+ m_services.append(service.data());
+ QTimer::singleShot(0, this, SLOT(startDebugging()));
+ }
+ } else {
+ SDEBUG("UNKNOWN RESPONSE PACKET:"
+ << quoteUnprintableLatin1(response) << parts);
+ }
+}
+
+void TcfEngine::startDebugging()
+{
+ //foreach (const QByteArray &service, m_services) {
+ // postCommand(CB(handleRunControlGetChildren),
+ // service, "getChildren", "\"\"");
+ //}
+
+ postCommand(C("Diagnostics", "getChildren", "\"\""),
+ CB(handleRunControlGetChildren));
+ postCommand(C("Streams", "getChildren", "\"\""));
+ postCommand(C("Expressions", "getChildren", "\"\""));
+ postCommand(C("SysMonitor", "getChildren", "\"\""));
+ //postCommand(C("FileSystem", "getChildren", "\"\""));
+ //postCommand(C("Processes", "getChildren", "\"\""));
+ //postCommand(CB(handleRunControlGetChildren), "LineNumbers", "getChildren");
+ //postCommand(CB(handleRunControlGetChildren), "Symbols", "getChildren");
+ //postCommand(CB(handleRunControlGetChildren), "StackTrace", "getChildren");
+ //postCommand(CB(handleRunControlGetChildren), "Registers", "getChildren");
+ //postCommand(CB(handleRunControlGetChildren), "Memory", "getChildren");
+ //postCommand(CB(handleRunControlGetChildren), "Breakpoints", "getChildren");
+ //postCommand(CB(handleRunControlGetChildren), "RunControl", "getChildren");
+ //postCommand(CB(handleRunControlGetChildren), "Locator", "getChildren");
+
+
+ //postCommand(CB(handleRunControlSuspend),
+ // "RunControl", "suspend", "\"Thread1\"");
+ //postCommand(CB(handleRunControlSuspend),
+ // "RunControl", "getContext", "\"P12318\"");
+
+ //postCommand(C("Locator", "sync"), CB(handleRunControlGetChildren));
+ //postCommand("Locator", "redirect", "ID");
+
+ //postCommand(C("FileSystem", "open", "\"/bin/ls\"", "1", "2", "3"),
+ // CB(handleRunControlGetChildren));
+ postCommand(C("FileSystem", "stat", "\"/bin/ls\""),
+ CB(handleRunControlGetChildren));
+}
+
+void TcfEngine::postCommand(const QByteArray &cmd,
+ TcfCommandCallback callback, const char *callbackName)
+{
+ static int token = 20;
+ ++token;
+
+ //const char marker_eom = -1;
+ //const char marker_eos = -2;
+ //const char marker_null = -3;
+
+ QByteArray ba = "C";
+ ba.append('\0');
+ ba.append(QByteArray::number(token));
+ ba.append('\0');
+ ba.append(cmd);
+ ba.append('\0');
+ ba.append('\3');
+ ba.append('\1');
+
+ TcfCommand tcf;
+ tcf.command = ba;
+ tcf.callback = callback;
+ tcf.callbackName = callbackName;
+ tcf.token = token;
+
+ m_cookieForToken[token] = tcf;
+
+ enqueueCommand(tcf);
+}
+
+// Congestion control does not seem to work that way. Basically it's
+// already too late when we get a flow control packet
+void TcfEngine::enqueueCommand(const TcfCommand &cmd)
+{
+#ifdef USE_CONGESTION_CONTROL
+ // congestion controled
+ if (m_congestion <= 0 && m_sendQueue.isEmpty()) {
+ //SDEBUG("DIRECT SEND" << cmd.toString());
+ sendCommandNow(cmd);
+ } else {
+ SDEBUG("QUEUE " << cmd.toString());
+ m_sendQueue.enqueue(cmd);
+ m_sendTimer.start();
+ }
+#else
+ // synchrounously
+ if (m_inAir == 0)
+ sendCommandNow(cmd);
+ else
+ m_sendQueue.enqueue(cmd);
+#endif
+}
+
+void TcfEngine::handleSendTimer()
+{
+ QTC_ASSERT(!m_sendQueue.isEmpty(), return);
+
+ if (m_congestion > 0) {
+ // not ready...
+ SDEBUG("WAITING FOR CONGESTION TO GO DOWN...");
+ m_sendTimer.start();
+ } else {
+ // go!
+ sendCommandNow(m_sendQueue.dequeue());
+ }
+}
+
+void TcfEngine::sendCommandNow(const TcfCommand &cmd)
+{
+ ++m_inAir;
+ int result = m_socket->write(cmd.command);
+ Q_UNUSED(result)
+ m_socket->flush();
+ showMessage(QString::number(cmd.token) + " " + cmd.toString(), LogInput);
+ SDEBUG("SEND " << cmd.toString()); //<< " " << QString::number(result));
+}
+
+void TcfEngine::acknowledgeResult()
+{
+#if !defined(USE_CONGESTION_CONTROL)
+ QTC_ASSERT(m_inAir == 1, /**/);
+ m_inAir = 0;
+ if (!m_sendQueue.isEmpty())
+ sendCommandNow(m_sendQueue.dequeue());
+#endif
+}
+
+void TcfEngine::handleRunControlSuspend(const JsonValue &data, const QVariant &)
+{
+ SDEBUG("HANDLE RESULT" << data.toString());
+}
+
+void TcfEngine::handleRunControlGetChildren(const JsonValue &data, const QVariant &)
+{
+ SDEBUG("HANDLE RUN CONTROL GET CHILDREN" << data.toString());
+}
+
+void TcfEngine::handleSysMonitorGetChildren(const JsonValue &data, const QVariant &)
+{
+ SDEBUG("HANDLE RUN CONTROL GET CHILDREN" << data.toString());
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Tooltip specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+static WatchData m_toolTip;
+static QPoint m_toolTipPos;
+static QHash<QString, WatchData> m_toolTipCache;
+
+void TcfEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
+{
+ Q_UNUSED(mousePos)
+ Q_UNUSED(editor)
+ Q_UNUSED(cursorPos)
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Watch specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void TcfEngine::assignValueInDebugger(const QString &expression,
+ const QString &value)
+{
+ XSDEBUG("ASSIGNING: " << expression + '=' + value);
+ updateLocals();
+}
+
+void TcfEngine::updateLocals()
+{
+}
+
+void TcfEngine::updateWatchData(const WatchData &)
+{
+ //qq->watchHandler()->rebuildModel();
+ showStatusMessage(tr("Stopped."), 5000);
+}
+
+void TcfEngine::updateSubItem(const WatchData &data0)
+{
+ Q_UNUSED(data0)
+ QTC_ASSERT(false, return);
+}
+
+IDebuggerEngine *createTcfEngine(DebuggerManager *manager)
+{
+ return new TcfEngine(manager);
+}
+
+} // namespace Internal
+} // namespace Debugger
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DEBUGGER_TCFENGINE_H
+#define DEBUGGER_TCFENGINE_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QHash>
+#include <QtCore/QMap>
+#include <QtCore/QObject>
+#include <QtCore/QPoint>
+#include <QtCore/QProcess>
+#include <QtCore/QQueue>
+#include <QtCore/QSet>
+#include <QtCore/QTimer>
+#include <QtCore/QVariant>
+
+#include <QtNetwork/QAbstractSocket>
+
+QT_BEGIN_NAMESPACE
+class QTcpSocket;
+QT_END_NAMESPACE
+
+#include "idebuggerengine.h"
+#include "debuggermanager.h"
+#include "json.h"
+
+namespace Debugger {
+namespace Internal {
+
+class ScriptAgent;
+class WatchData;
+
+class TcfEngine : public IDebuggerEngine
+{
+ Q_OBJECT
+
+public:
+ explicit TcfEngine(DebuggerManager *parent);
+ ~TcfEngine();
+
+private:
+ // IDebuggerEngine implementation
+ void executeStep();
+ void executeStepOut();
+ void executeNext();
+ void executeStepI();
+ void executeNextI();
+
+ void shutdown();
+ void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos);
+ void startDebugger();
+ void exitDebugger();
+
+ void continueInferior();
+ Q_SLOT void runInferior();
+ void interruptInferior();
+
+ void executeRunToLine(const QString &fileName, int lineNumber);
+ void executeRunToFunction(const QString &functionName);
+ void executeJumpToLine(const QString &fileName, int lineNumber);
+
+ void activateFrame(int index);
+ void selectThread(int index);
+
+ void attemptBreakpointSynchronization();
+
+ void assignValueInDebugger(const QString &expr, const QString &value);
+ void executeDebuggerCommand(const QString & command);
+
+ void loadSymbols(const QString &moduleName);
+ void loadAllSymbols();
+ void requestModuleSymbols(const QString &moduleName);
+ void reloadModules();
+ void reloadRegisters() {}
+ void reloadSourceFiles() {}
+ void reloadFullStack() {}
+
+ bool supportsThreads() const { return true; }
+ void maybeBreakNow(bool byFunction);
+ void updateWatchData(const WatchData &data);
+ void updateLocals();
+ void updateSubItem(const WatchData &data);
+
+ Q_SLOT void socketConnected();
+ Q_SLOT void socketDisconnected();
+ Q_SLOT void socketError(QAbstractSocket::SocketError);
+ Q_SLOT void socketReadyRead();
+
+ void handleResponse(const QByteArray &ba);
+ void handleRunControlSuspend(const JsonValue &response, const QVariant &);
+ void handleRunControlGetChildren(const JsonValue &response, const QVariant &);
+ void handleSysMonitorGetChildren(const JsonValue &response, const QVariant &);
+
+private:
+ Q_SLOT void startDebugging();
+
+ typedef void (TcfEngine::*TcfCommandCallback)
+ (const JsonValue &record, const QVariant &cookie);
+
+ struct TcfCommand
+ {
+ TcfCommand() : flags(0), token(-1), callback(0), callbackName(0) {}
+
+ QString toString() const;
+
+ int flags;
+ int token;
+ TcfCommandCallback callback;
+ const char *callbackName;
+ QByteArray command;
+ QVariant cookie;
+ };
+
+ void postCommand(const QByteArray &cmd,
+ TcfCommandCallback callback = 0, const char *callbackName = 0);
+ void sendCommandNow(const TcfCommand &command);
+
+ QHash<int, TcfCommand> m_cookieForToken;
+
+ QQueue<TcfCommand> m_sendQueue;
+
+ // timer based congestion control. does not seem to work well.
+ void enqueueCommand(const TcfCommand &command);
+ Q_SLOT void handleSendTimer();
+ int m_congestion;
+ QTimer m_sendTimer;
+
+ // synchrounous communication
+ void acknowledgeResult();
+ int m_inAir;
+
+ QTcpSocket *m_socket;
+ QByteArray m_inbuffer;
+ QList<QByteArray> m_services;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_TCFENGINE_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "threadshandler.h"
+
+namespace Debugger {
+namespace Internal {
+
+////////////////////////////////////////////////////////////////////////
+//
+// ThreadsHandler
+//
+///////////////////////////////////////////////////////////////////////
+
+ThreadData::ThreadData(int threadId)
+{
+ notifyRunning();
+ id = threadId;
+}
+
+void ThreadData::notifyRunning()
+{
+ address = 0;
+ function.clear();
+ fileName.clear();
+ frameLevel = -1;
+ state.clear();
+ lineNumber = -1;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// ThreadsHandler
+//
+///////////////////////////////////////////////////////////////////////
+
+ThreadsHandler::ThreadsHandler(QObject *parent) :
+ QAbstractTableModel(parent),
+ m_currentIndex(0),
+ m_positionIcon(QLatin1String(":/debugger/images/location_16.png")),
+ m_emptyIcon(QLatin1String(":/debugger/images/debugger_empty_14.png"))
+{
+}
+
+int ThreadsHandler::rowCount(const QModelIndex &parent) const
+{
+ // Since the stack is not a tree, row count is 0 for any valid parent
+ return parent.isValid() ? 0 : m_threads.size();
+}
+
+int ThreadsHandler::columnCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? 0 : int(ThreadData::ColumnCount);
+}
+
+QVariant ThreadsHandler::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+ const int row = index.row();
+ if (row >= m_threads.size())
+ return QVariant();
+ const ThreadData &thread = m_threads.at(row);
+
+ if (role == Qt::DisplayRole) {
+ switch (index.column()) {
+ case ThreadData::IdColumn:
+ return thread.id;
+ case ThreadData::FunctionColumn:
+ return thread.function;
+ case ThreadData::FileColumn:
+ return thread.fileName;
+ case ThreadData::LineColumn:
+ return thread.lineNumber >= 0 ? QString::number(thread.lineNumber) : QString();
+ case ThreadData::AddressColumn:
+ return thread.address > 0 ? QLatin1String("0x") + QString::number(thread.address, 16) : QString();
+ case ThreadData::CoreColumn:
+ return thread.core;
+ case ThreadData::StateColumn:
+ return thread.state;
+ }
+ } else if (role == Qt::ToolTipRole) {
+ if (thread.address == 0)
+ return tr("Thread: %1").arg(thread.id);
+ // Stopped
+ if (thread.fileName.isEmpty())
+ return tr("Thread: %1 at %2 (0x%3)").arg(thread.id).arg(thread.function).arg(thread.address, 0, 16);
+ return tr("Thread: %1 at %2, %3:%4 (0x%5)").
+ arg(thread.id).arg(thread.function, thread.fileName).arg(thread.lineNumber).arg(thread.address, 0, 16);
+ } else if (role == Qt::DecorationRole && index.column() == 0) {
+ // Return icon that indicates whether this is the active stack frame
+ return (index.row() == m_currentIndex) ? m_positionIcon : m_emptyIcon;
+ }
+
+ return QVariant();
+}
+
+QVariant ThreadsHandler::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
+ return QVariant();
+ switch (section) {
+ case ThreadData::IdColumn:
+ return tr("Thread ID");
+ case ThreadData::FunctionColumn:
+ return tr("Function");
+ case ThreadData::FileColumn:
+ return tr("File");
+ case ThreadData::LineColumn:
+ return tr("Line");
+ case ThreadData::AddressColumn:
+ return tr("Address");
+ case ThreadData::CoreColumn:
+ return tr("Core");
+ case ThreadData::StateColumn:
+ return tr("State");
+ }
+ return QVariant();
+}
+
+int ThreadsHandler::currentThreadId() const
+{
+ if (m_currentIndex < 0 || m_currentIndex >= m_threads.size())
+ return -1;
+ return m_threads[m_currentIndex].id;
+}
+
+void ThreadsHandler::setCurrentThread(int index)
+{
+ if (index == m_currentIndex)
+ return;
+
+ // Emit changed for previous frame
+ QModelIndex i = ThreadsHandler::index(m_currentIndex, 0);
+ emit dataChanged(i, i);
+
+ m_currentIndex = index;
+
+ // Emit changed for new frame
+ i = ThreadsHandler::index(m_currentIndex, 0);
+ emit dataChanged(i, i);
+}
+
+void ThreadsHandler::setThreads(const QList<ThreadData> &threads)
+{
+ m_threads = threads;
+ if (m_currentIndex >= m_threads.size())
+ m_currentIndex = m_threads.size() - 1;
+ reset();
+}
+
+QList<ThreadData> ThreadsHandler::threads() const
+{
+ return m_threads;
+}
+
+void ThreadsHandler::removeAll()
+{
+ m_threads.clear();
+ m_currentIndex = 0;
+ reset();
+}
+
+void ThreadsHandler::notifyRunning()
+{
+ // Threads stopped (that is, address != 0 showing)?
+ if (m_threads.empty())
+ return;
+ if (m_threads.front().address == 0)
+ return;
+ const QList<ThreadData>::iterator end = m_threads.end();
+ for (QList<ThreadData>::iterator it = m_threads.begin(); it != end; ++it)
+ it->notifyRunning();
+ emit dataChanged(index(0, 1),
+ index(m_threads.size() - 1, ThreadData::ColumnCount - 1));
+}
+
+} // namespace Internal
+} // namespace Debugger
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef THREADSHANDLER_H
+#define THREADSHANDLER_H
+
+#include <QtCore/QAbstractTableModel>
+#include <QtCore/QList>
+
+#include <QtGui/QIcon>
+
+
+namespace Debugger {
+namespace Internal {
+
+////////////////////////////////////////////////////////////////////////
+//
+// ThreadData
+//
+////////////////////////////////////////////////////////////////////////
+
+/*! A structure containing information about a single thread */
+struct ThreadData
+{
+ ThreadData(int threadId = 0);
+
+ enum {
+ IdColumn,
+ AddressColumn,
+ FunctionColumn,
+ FileColumn,
+ LineColumn,
+ StateColumn,
+ CoreColumn,
+ ColumnCount = CoreColumn
+ };
+
+ // Permanent data.
+ int id;
+ QString targetId;
+ QString core;
+
+ // State information when stopped
+ void notifyRunning(); // Clear state information
+
+ int frameLevel;
+ quint64 address;
+ QString function;
+ QString fileName;
+ QString state;
+ int lineNumber;
+};
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// ThreadsHandler
+//
+////////////////////////////////////////////////////////////////////////
+
+/*! A model to represent the running threads in a QTreeView or ComboBox */
+class ThreadsHandler : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ ThreadsHandler(QObject *parent = 0);
+
+ int currentThreadId() const;
+ void setCurrentThread(int index);
+ void selectThread(int index);
+ void setThreads(const QList<ThreadData> &threads);
+ void removeAll();
+ QList<ThreadData> threads() const;
+ QAbstractItemModel *threadsModel() { return this; }
+
+ // Clear out all frame information
+ void notifyRunning();
+
+private:
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+
+private:
+ QList<ThreadData> m_threads;
+ int m_currentIndex;
+ const QIcon m_positionIcon;
+ const QIcon m_emptyIcon;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // THREADSHANDLER_H
m_root->parent = 0;
switch (m_type) {
+ case ReturnWatch:
+ m_root->iname = "return";
+ m_root->name = WatchHandler::tr("Return Value");
+ break;
case LocalsWatch:
m_root->iname = "local";
m_root->name = WatchHandler::tr("Locals");
return v;
}
+// Get a pointer address from pointer values reported by the debugger.
+// Fix CDB formatting of pointers "0x00000000`000003fd class foo *",
+// check gdb formatting of characters.
+static inline quint64 pointerValue(QString data)
+{
+ if (data.isEmpty() || !data.startsWith(QLatin1String("0x")))
+ return 0;
+ data.remove(0, 2);
+ const int blankPos = data.indexOf(QLatin1Char(' '));
+ if (blankPos != -1)
+ data.truncate(blankPos);
+ data.remove(QLatin1Char('`'));
+ bool ok;
+ const quint64 address = data.toULongLong(&ok, 16);
+ return ok ? address : quint64(0);
+}
+
QVariant WatchModel::data(const QModelIndex &idx, int role) const
{
const WatchItem *item = watchItem(idx);
case IndividualFormatRole:
return m_handler->m_individualFormats.value(data.addr, -1);
- case AddressRole: {
- if (!data.addr.isEmpty())
- return data.addr;
- bool ok;
- (void) data.value.toULongLong(&ok, 0);
- if (ok)
- return data.value;
- return QVariant();
- }
+ case AddressRole:
+ if (!data.addr.isEmpty()) {
+ bool ok;
+ const quint64 address = data.addr.toULongLong(&ok, 16);
+ if (ok)
+ return QVariant(address);
+ }
+ return QVariant(quint64(0));
+
+ case RawValueRole:
+ return data.value;
+ case PointerValue:
+ if (isPointerType(data.type))
+ return pointerValue(data.value);
+ return QVariant(quint64(0));
default:
break;
}
static const ItemFlags notEditable =
ItemIsSelectable
- | ItemIsDragEnabled
- | ItemIsDropEnabled
+ // | ItemIsDragEnabled
+ // | ItemIsDropEnabled
// | ItemIsUserCheckable
// | ItemIsTristate
| ItemIsEnabled;
m_expandPointers = true;
m_inChange = false;
+ m_return = new WatchModel(this, ReturnWatch);
m_locals = new WatchModel(this, LocalsWatch);
m_watchers = new WatchModel(this, WatchersWatch);
m_tooltips = new WatchModel(this, TooltipsWatch);
void WatchHandler::beginCycle()
{
++generationCounter;
+ m_return->beginCycle();
m_locals->beginCycle();
m_watchers->beginCycle();
m_tooltips->beginCycle();
void WatchHandler::endCycle()
{
+ m_return->endCycle();
m_locals->endCycle();
m_watchers->endCycle();
m_tooltips->endCycle();
void WatchHandler::cleanup()
{
m_expandedINames.clear();
+ m_return->reinitialize();
m_locals->reinitialize();
m_tooltips->reinitialize();
+ m_return->m_fetchTriggered.clear();
m_locals->m_fetchTriggered.clear();
m_watchers->m_fetchTriggered.clear();
m_tooltips->m_fetchTriggered.clear();
void WatchHandler::emitAllChanged()
{
+ m_return->emitAllChanged();
m_locals->emitAllChanged();
m_watchers->emitAllChanged();
m_tooltips->emitAllChanged();
WatchModel *WatchHandler::model(WatchType type) const
{
switch (type) {
+ case ReturnWatch: return m_return;
case LocalsWatch: return m_locals;
case WatchersWatch: return m_watchers;
case TooltipsWatch: return m_tooltips;
WatchModel *WatchHandler::modelForIName(const QByteArray &iname) const
{
+ if (iname.startsWith("return"))
+ return m_return;
if (iname.startsWith("local"))
return m_locals;
if (iname.startsWith("tooltip"))
void WatchHandler::setFormat(const QString &type, int format)
{
- m_typeFormats[type] = format;
+ if (format == -1)
+ m_typeFormats.remove(type);
+ else
+ m_typeFormats[type] = format;
saveTypeFormats();
+ m_return->emitDataChanged(1);
m_locals->emitDataChanged(1);
m_watchers->emitDataChanged(1);
m_tooltips->emitDataChanged(1);
class WatchItem;
class WatchHandler;
-enum WatchType { LocalsWatch, WatchersWatch, TooltipsWatch };
+enum WatchType { ReturnWatch, LocalsWatch, WatchersWatch, TooltipsWatch };
enum WatchRoles
{
TypeFormatListRole,
TypeFormatRole, // Used to communicate alternative formats to the view.
IndividualFormatRole,
- AddressRole, // Some memory address related to the object.
+ AddressRole, // Memory address of variable as quint64.
+ RawValueRole, // Unformatted value as string.
+ PointerValue // Pointer value (address) as quint64.
};
enum IntegerFormat
// Items expanded in the Locals & Watchers view.
QSet<QByteArray> m_expandedINames;
+ WatchModel *m_return;
WatchModel *m_locals;
WatchModel *m_watchers;
WatchModel *m_tooltips;
const CPlusPlus::Document::Ptr doc = docIt.value();
// Look at symbol at line and find its function. Either it is the
// function itself or some expression/variable.
- const CPlusPlus::Symbol *symbolAtLine = doc->findSymbolAt(line, 0);
+ const CPlusPlus::Symbol *symbolAtLine = doc->lastVisibleSymbolAt(line, 0);
if (!symbolAtLine)
return 4;
// First figure out the function to do a safety name check
return QString();
QString expr = plaintext->textCursor().selectedText();
- if (expr.isEmpty()) {
+ CppTools::CppModelManagerInterface *modelManager = ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
+ if (expr.isEmpty() && modelManager) {
QTextCursor tc(plaintext->document());
tc.setPosition(pos);
tc.movePosition(QTextCursor::EndOfWord);
// Fetch the expression's code.
- CPlusPlus::ExpressionUnderCursor expressionUnderCursor;
+ CPlusPlus::ExpressionUnderCursor expressionUnderCursor(modelManager->tokenCache(editor));
expr = expressionUnderCursor(tc);
*column = tc.columnNumber();
*line = tc.blockNumber();
if (function && !expr.isEmpty())
if (const Core::IFile *file = editor->file())
- if (CppTools::CppModelManagerInterface *modelManager = ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>())
+ if (modelManager)
*function = CppTools::AbstractEditorSupport::functionAt(modelManager, file->fileName(), *line, *column);
return expr;
break;
case StdDequeType:
extraArgs[1] = zero;
+ break;
case StdStackType:
// remove 'std::allocator<...>':
extraArgs[1] = zero;
#include "watchwindow.h"
#include "watchhandler.h"
+#include "breakpoint.h"
+#include "breakhandler.h"
#include "debuggeractions.h"
#include "debuggeragents.h"
#include "debuggerdialogs.h"
//QTreeView::dropEvent(ev);
}
+static inline void toggleWatchPoint(DebuggerManager *manager, quint64 address)
+{
+ const QByteArray addressBA = QByteArray("0x") + QByteArray::number(address, 16);
+ const int index = manager->breakHandler()->findWatchPointIndexByAddress(addressBA);
+ if (index == -1) {
+ BreakpointData *data = new BreakpointData;
+ data->type = BreakpointData::WatchpointType;
+ data->address = addressBA;
+ manager->breakHandler()->appendBreakpoint(data);
+ } else {
+ manager->breakHandler()->removeBreakpoint(index);
+ }
+ manager->attemptBreakpointSynchronization();
+}
+
void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
{
const QModelIndex idx = indexAt(ev->pos());
const QModelIndex mi0 = idx.sibling(idx.row(), 0);
const QModelIndex mi1 = idx.sibling(idx.row(), 1);
const QModelIndex mi2 = idx.sibling(idx.row(), 2);
- const QString addr = model()->data(mi0, AddressRole).toString();
+ const quint64 address = model()->data(mi0, AddressRole).toULongLong();
+ const quint64 pointerValue = model()->data(mi0, PointerValue).toULongLong();
const QString exp = model()->data(mi0, ExpressionRole).toString();
const QString type = model()->data(mi2).toString();
const QStringList alternativeFormats =
model()->data(mi0, TypeFormatListRole).toStringList();
const int typeFormat =
- qMax(int(DecimalFormat), model()->data(mi0, TypeFormatRole).toInt());
+ model()->data(mi0, TypeFormatRole).toInt();
const int individualFormat =
model()->data(mi0, IndividualFormatRole).toInt();
const int effectiveIndividualFormat =
QMenu typeFormatMenu;
QList<QAction *> typeFormatActions;
+ QAction *clearTypeFormatAction = 0;
if (idx.isValid()) {
typeFormatMenu.setTitle(
tr("Change Format for Type \"%1\"").arg(type));
if (alternativeFormats.isEmpty()) {
typeFormatMenu.setEnabled(false);
} else {
+ clearTypeFormatAction = typeFormatMenu.addAction(tr("Clear"));
+ clearTypeFormatAction->setEnabled(typeFormat != -1);
+ clearTypeFormatAction->setCheckable(true);
+ clearTypeFormatAction->setChecked(typeFormat == -1);
+ typeFormatMenu.addSeparator();
for (int i = 0; i != alternativeFormats.size(); ++i) {
const QString format = alternativeFormats.at(i);
QAction *act = new QAction(format, &typeFormatMenu);
QMenu individualFormatMenu;
QList<QAction *> individualFormatActions;
QAction *clearIndividualFormatAction = 0;
- if (idx.isValid() && !addr.isEmpty()) {
+ if (idx.isValid() && address) {
individualFormatMenu.setTitle(
- tr("Change Format for Object at %1").arg(addr));
+ tr("Change Format for Object at 0x%1").arg(address, 0, 16));
if (alternativeFormats.isEmpty()) {
individualFormatMenu.setEnabled(false);
} else {
clearIndividualFormatAction = individualFormatMenu.addAction(tr("Clear"));
clearIndividualFormatAction->setEnabled(individualFormat != -1);
+ clearIndividualFormatAction->setCheckable(true);
+ clearIndividualFormatAction->setChecked(individualFormat == -1);
individualFormatMenu.addSeparator();
for (int i = 0; i != alternativeFormats.size(); ++i) {
const QString format = alternativeFormats.at(i);
QAction *actSelectWidgetToWatch = menu.addAction(tr("Select Widget to Watch"));
actSelectWidgetToWatch->setEnabled(canHandleWatches);
- const QString address = model()->data(mi0, AddressRole).toString();
- QAction *actWatchKnownMemory = 0;
- QAction *actWatchUnknownMemory = new QAction(tr("Open Memory Editor..."), &menu);
+ QAction *actOpenMemoryEditAtVariableAddress = 0;
+ QAction *actOpenMemoryEditAtPointerValue = 0;
+ QAction *actOpenMemoryEditor =
+ new QAction(tr("Open Memory Editor..."), &menu);
const bool canShowMemory = engineCapabilities & ShowMemoryCapability;
- actWatchUnknownMemory->setEnabled(actionsEnabled && canShowMemory);
+ actOpenMemoryEditor->setEnabled(actionsEnabled && canShowMemory);
+
+ // Offer to open address pointed to or variable address.
+ const bool createPointerActions = pointerValue && pointerValue != address;
- if (canShowMemory && !address.isEmpty())
- actWatchKnownMemory =
- new QAction(tr("Open Memory Editor at %1").arg(address), &menu);
+ if (canShowMemory && address)
+ actOpenMemoryEditAtVariableAddress =
+ new QAction(tr("Open Memory Editor at Object's Address (0x%1)").arg(address, 0, 16), &menu);
+ if (createPointerActions)
+ actOpenMemoryEditAtPointerValue =
+ new QAction(tr("Open Memory Editor at Referenced Address (0x%1)").arg(pointerValue, 0, 16), &menu);
menu.addSeparator();
+ QAction *actSetWatchPointAtVariableAddress = 0;
+ QAction *actSetWatchPointAtPointerValue= 0;
+ const bool canSetWatchpoint = engineCapabilities & WatchpointCapability;
+ if (canSetWatchpoint && address) {
+ actSetWatchPointAtVariableAddress =
+ new QAction(tr("Break on Changes at Object's Address (0x%1)").arg(address, 0, 16), &menu);
+ actSetWatchPointAtVariableAddress->setCheckable(true);
+ actSetWatchPointAtVariableAddress->setChecked(m_manager->breakHandler()->watchPointAt(address));
+ if (createPointerActions) {
+ actSetWatchPointAtPointerValue =
+ new QAction(tr("Break on Changes at Referenced Address (0x%1)").arg(pointerValue, 0, 16), &menu);
+ actSetWatchPointAtPointerValue->setCheckable(true);
+ actSetWatchPointAtPointerValue->setChecked(m_manager->breakHandler()->watchPointAt(pointerValue));
+ }
+ } else {
+ actSetWatchPointAtVariableAddress =
+ new QAction(tr("Break on Changing Contents"), &menu);
+ actSetWatchPointAtVariableAddress->setEnabled(false);
+ }
+
QAction *actWatchOrRemove;
if (m_type == LocalsType) {
actWatchOrRemove = theDebuggerAction(WatchExpression)->updatedAction(exp);
menu.addAction(actSelectWidgetToWatch);
menu.addMenu(&typeFormatMenu);
menu.addMenu(&individualFormatMenu);
- if (actWatchKnownMemory)
- menu.addAction(actWatchKnownMemory);
- menu.addAction(actWatchUnknownMemory);
+ if (actOpenMemoryEditAtVariableAddress)
+ menu.addAction(actOpenMemoryEditAtVariableAddress);
+ if (actOpenMemoryEditAtPointerValue)
+ menu.addAction(actOpenMemoryEditAtPointerValue);
+ menu.addAction(actOpenMemoryEditor);
+ menu.addAction(actSetWatchPointAtVariableAddress);
+ if (actSetWatchPointAtPointerValue)
+ menu.addAction(actSetWatchPointAtPointerValue);
menu.addSeparator();
menu.addAction(theDebuggerAction(RecheckDebuggingHelpers));
menu.addAction(theDebuggerAction(SettingsDialog));
QAction *act = menu.exec(ev->globalPos());
+ if (act == 0)
+ return;
if (act == actAdjustColumnWidths) {
resizeColumnsToContents();
} else if (act == actInsertNewWatchItem) {
theDebuggerAction(WatchExpression)
->trigger(WatchHandler::watcherEditPlaceHolder());
- } else if (actWatchKnownMemory != 0 && act == actWatchKnownMemory) {
+ } else if (act == actOpenMemoryEditAtVariableAddress) {
(void) new MemoryViewAgent(m_manager, address);
- } else if (actWatchUnknownMemory != 0 && act == actWatchUnknownMemory) {
+ } else if (act == actOpenMemoryEditAtPointerValue) {
+ (void) new MemoryViewAgent(m_manager, pointerValue);
+ } else if (act == actOpenMemoryEditor) {
AddressDialog dialog;
if (dialog.exec() == QDialog::Accepted) {
(void) new MemoryViewAgent(m_manager, dialog.address());
}
+ } else if (act == actSetWatchPointAtVariableAddress) {
+ toggleWatchPoint(m_manager, address);
+ } else if (act == actSetWatchPointAtPointerValue) {
+ toggleWatchPoint(m_manager, pointerValue);
} else if (act == actSelectWidgetToWatch) {
grabMouse(Qt::CrossCursor);
m_grabbing = true;
} else if (act == actClearCodeModelSnapshot) {
m_manager->clearCppCodeModelSnapshot();
- } else if (clearIndividualFormatAction && act == clearIndividualFormatAction) {
+ } else if (act == clearTypeFormatAction) {
+ model()->setData(mi1, -1, TypeFormatRole);
+ } else if (act == clearIndividualFormatAction) {
model()->setData(mi1, -1, IndividualFormatRole);
} else {
for (int i = 0; i != typeFormatActions.size(); ++i) {
Q_OBJECT
public:
- enum Type { LocalsType, TooltipType, WatchersType };
+ enum Type { ReturnType, LocalsType, TooltipType, WatchersType };
WatchWindow(Type type, DebuggerManager *manager, QWidget *parent = 0);
void setType(Type type) { m_type = type; }
-<plugin name="Designer" version="2.0.80" compatVersion="2.0.80">
+<plugin name="Designer" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Qt Designer integration.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
<!-- For compiling with CPP support enabled -->
- <dependency name="CppEditor" version="2.0.80"/>
+ <dependency name="CppEditor" version="2.1.80"/>
</dependencyList>
</plugin>
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/mimedatabase.h>
#include <texteditor/basetextdocument.h>
#include <texteditor/plaintexteditor.h>
connect(&(d->m_file), SIGNAL(reload(QString)), this, SLOT(slotOpen(QString)));
// Force update of open editors model.
connect(&(d->m_file), SIGNAL(saved()), this, SIGNAL(changed()));
+ connect(&(d->m_file), SIGNAL(changed()), this, SIGNAL(changed()));
+ connect(this, SIGNAL(changed()), this, SLOT(configureXmlEditor()));
}
FormWindowEditor::~FormWindowEditor()
syncXmlEditor(contents());
}
+void FormWindowEditor::configureXmlEditor() const
+{
+ TextEditor::PlainTextEditor *editor =
+ qobject_cast<TextEditor::PlainTextEditor *>(d->m_textEditable.editor());
+ if (editor)
+ editor->configure(Core::ICore::instance()->mimeDatabase()->findByFile(
+ d->m_file.fileName()));
+}
+
void FormWindowEditor::syncXmlEditor(const QString &contents)
{
d->m_textEditable.editor()->setPlainText(contents);
public slots:
void syncXmlEditor();
+ void configureXmlEditor() const;
private slots:
void slotOpen(const QString &fileName);
return true;
}
+void FormWindowFile::rename(const QString &newName)
+{
+ m_formWindow->setFileName(newName);
+ QFileInfo fi(newName);
+ m_fileName = fi.absoluteFilePath();
+ emit setDisplayName(fi.fileName());
+ emit changed();
+}
+
QString FormWindowFile::fileName() const
{
return m_fileName;
virtual QString defaultPath() const;
virtual QString suggestedFileName() const;
virtual QString mimeType() const;
+ virtual void rename(const QString &newName);
// Internal
void setSuggestedFileName(const QString &fileName);
#include <cplusplus/Literals.h>
#include <cplusplus/Scope.h>
#include <cplusplus/Control.h>
-#include <cplusplus/LookupContext.h>
+#include <cplusplus/TranslationUnit.h>
#include <coreplugin/icore.h>
#include <coreplugin/editormanager/editormanager.h>
#include <extensionsystem/pluginmanager.h>
return 0;
}
-static const Function *findDeclaration(const Class *cl, const QString &functionName)
+static Function *findDeclaration(const Class *cl, const QString &functionName)
{
const QString funName = QString::fromUtf8(QMetaObject::normalizedSignature(functionName.toUtf8()));
const unsigned mCount = cl->memberCount();
// we are only interested in declarations of methods
const Overview overview;
for (unsigned j = 0; j < mCount; j++) { // go through all members
- if (const Declaration *decl = cl->memberAt(j)->asDeclaration())
- if (const Function *fun = decl->type()->asFunctionType()) {
+ if (Declaration *decl = cl->memberAt(j)->asDeclaration())
+ if (Function *fun = decl->type()->asFunctionType()) {
// Format signature
QString memberFunction = overview.prettyName(fun->name());
memberFunction += QLatin1Char('(');
return 0;
}
-// TODO: remove me, see below
-static bool isCompatible(const Name *name, const Name *otherName)
-{
- if (const NameId *nameId = name->asNameId()) {
- if (const TemplateNameId *otherTemplId = otherName->asTemplateNameId())
- return nameId->identifier()->isEqualTo(otherTemplId->identifier());
- } else if (const TemplateNameId *templId = name->asTemplateNameId()) {
- if (const NameId *otherNameId = otherName->asNameId())
- return templId->identifier()->isEqualTo(otherNameId->identifier());
- }
-
- return name->isEqualTo(otherName);
-}
-
-// TODO: remove me, see below
-static bool isCompatible(const Function *definition, const Symbol *declaration, const QualifiedNameId *declarationName)
-{
- Function *declTy = declaration->type()->asFunctionType();
- if (! declTy)
- return false;
-
- const Name *definitionName = definition->name();
- if (const QualifiedNameId *q = definitionName->asQualifiedNameId()) {
- if (! isCompatible(q->unqualifiedNameId(), declaration->name()))
- return false;
- else if (q->nameCount() > declarationName->nameCount())
- return false;
- else if (declTy->argumentCount() != definition->argumentCount())
- return false;
- else if (declTy->isConst() != definition->isConst())
- return false;
- else if (declTy->isVolatile() != definition->isVolatile())
- return false;
-
- for (unsigned i = 0; i < definition->argumentCount(); ++i) {
- Symbol *arg = definition->argumentAt(i);
- Symbol *otherArg = declTy->argumentAt(i);
- if (! arg->type().isEqualTo(otherArg->type()))
- return false;
- }
-
- for (unsigned i = 0; i != q->nameCount(); ++i) {
- const Name *n = q->nameAt(q->nameCount() - i - 1);
- const Name *m = declarationName->nameAt(declarationName->nameCount() - i - 1);
- if (! isCompatible(n, m))
- return false;
- }
- return true;
- } else {
- // ### TODO: implement isCompatible for unqualified name ids.
- }
- return false;
-}
-
// TODO: remove me, this is taken from cppeditor.cpp. Find some common place for this method
-static Document::Ptr findDefinition(const Function *functionDeclaration, int *line)
+static Document::Ptr findDefinition(Function *functionDeclaration, int *line)
{
- CppTools::CppModelManagerInterface *cppModelManager = cppModelManagerInstance();
- if (!cppModelManager)
- return Document::Ptr();
+ if (CppTools::CppModelManagerInterface *cppModelManager = cppModelManagerInstance()) {
+ const Snapshot snapshot = cppModelManager->snapshot();
- QVector<const Name *> qualifiedName;
- Scope *scope = functionDeclaration->scope();
- for (; scope; scope = scope->enclosingScope()) {
- if (scope->isClassScope() || scope->isNamespaceScope()) {
- if (scope->owner() && scope->owner()->name()) {
- const Name *scopeOwnerName = scope->owner()->name();
- if (const QualifiedNameId *q = scopeOwnerName->asQualifiedNameId()) {
- for (unsigned i = 0; i < q->nameCount(); ++i) {
- qualifiedName.prepend(q->nameAt(i));
+ if (Symbol *def = snapshot.findMatchingDefinition(functionDeclaration)) {
+ if (line)
+ *line = def->line();
-}
- } else {
- qualifiedName.prepend(scopeOwnerName);
- }
- }
+ return snapshot.document(QString::fromUtf8(def->fileName(), def->fileNameLength()));
}
}
- qualifiedName.append(functionDeclaration->name());
-
- Control control;
- const QualifiedNameId *q = control.qualifiedNameId(&qualifiedName[0], qualifiedName.size());
- LookupContext context(&control);
- const Snapshot documents = cppModelManager->snapshot();
- foreach (Document::Ptr doc, documents) {
- QList<Scope *> visibleScopes;
- visibleScopes.append(doc->globalSymbols());
- visibleScopes = context.expand(visibleScopes);
- foreach (Scope *visibleScope, visibleScopes) {
- Symbol *symbol = 0;
- if (const NameId *nameId = q->unqualifiedNameId()->asNameId())
- symbol = visibleScope->lookat(nameId->identifier());
- else if (const DestructorNameId *dtorId = q->unqualifiedNameId()->asDestructorNameId())
- symbol = visibleScope->lookat(dtorId->identifier());
- else if (const TemplateNameId *templNameId = q->unqualifiedNameId()->asTemplateNameId())
- symbol = visibleScope->lookat(templNameId->identifier());
- else if (const OperatorNameId *opId = q->unqualifiedNameId()->asOperatorNameId())
- symbol = visibleScope->lookat(opId->kind());
- // ### cast operators
- for (; symbol; symbol = symbol->next()) {
- if (! symbol->isFunction())
- continue;
- else if (! isCompatible(symbol->asFunction(), functionDeclaration, q))
- continue;
- *line = symbol->line(); // TODO: shift the line so that we are inside a function. Maybe just find the nearest '{'?
- return doc;
- }
- }
- }
return Document::Ptr();
-
}
static bool isEndingQuote(const QString &contents, int quoteIndex)
return qobject_cast<ITextEditable *>(TextEditor::BaseTextEditor::openEditorAt(fileName, line, column));
}
-static void addDeclaration(const QString &docFileName, const Class *cl, const QString &functionName)
+static void addDeclaration(Document::Ptr doc, const Class *cl, const QString &functionName)
{
+ const QString docFileName = doc->fileName();
+ TranslationUnit *unit = doc->translationUnit();
QString declaration = QLatin1String("void ");
declaration += functionName;
declaration += QLatin1String(";\n");
const int column = fun->column();
if (ITextEditable *editable = editableAt(docFileName, line, column)) {
unsigned dl, dc; // this position is the beginning of return value: "^void foo(...)"
- decl->getStartPosition(&dl, &dc);
+ unit->getPosition(decl->startOffset(), &dl, &dc);
dc--; // if the first character in line is 'v' coming from "void" getStartPosition returns 1, not 0, so we always decrement it.
editable->gotoLine(dl, dc);
editable->position(ITextEditor::StartOfLine);
int line = 0;
Document::Ptr sourceDoc;
- if (const Function *fun = findDeclaration(cl, functionName)) {
+ if (Function *fun = findDeclaration(cl, functionName)) {
sourceDoc = findDefinition(fun, &line);
if (!sourceDoc) {
// add function definition to cpp file
}
} else {
// add function declaration to cl
- addDeclaration(doc->fileName(), cl, functionNameWithParameterNames);
+ addDeclaration(doc, cl, functionNameWithParameterNames);
// add function definition to cpp file
sourceDoc = addDefinition(docTable, doc->fileName(), className, functionNameWithParameterNames, &line);
-<plugin name="FakeVim" version="2.0.80" compatVersion="2.0.80">
+<plugin name="FakeVim" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>VI-style keyboard navigation.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="CppEditor" version="2.0.80"/><!-- Plugin adds items to the editor's context menu -->
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
- <dependency name="Core" version="2.0.80"/>
+ <dependency name="CppEditor" version="2.1.80"/><!-- Plugin adds items to the editor's context menu -->
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
+ <dependency name="Core" version="2.1.80"/>
</dependencyList>
</plugin>
// Helper functions for indenting/
bool isElectricCharacter(QChar c) const;
void indentSelectedText(QChar lastTyped = QChar());
- int indentText(const Range &range, QChar lastTyped = QChar());
+ void indentText(const Range &range, QChar lastTyped = QChar());
void shiftRegionLeft(int repeat = 1);
void shiftRegionRight(int repeat = 1);
{
return submode == DeleteSubMode
|| submode == YankSubMode
- || submode == ChangeSubMode;
+ || submode == ChangeSubMode
+ || submode == IndentSubMode
+ || submode == ShiftLeftSubMode
+ || submode == ShiftRightSubMode;
}
EventResult FakeVimHandler::Private::handleCommandSubSubMode(const Input &input)
selectBlockTextObject(m_subsubdata.is('i'), '(', ')');
else if (input.is('<') || input.is('>'))
selectBlockTextObject(m_subsubdata.is('i'), '<', '>');
+ else if (input.is('{') || input.is('}') || input.is('B'))
+ selectBlockTextObject(m_subsubdata.is('i'), '{', '}');
else if (input.is('"') || input.is('\'') || input.is('`'))
selectQuotedStringTextObject(m_subsubdata.is('i'), input.key());
m_subsubmode = NoSubSubMode;
setDotCommand("%1==", endLine - beginLine + 1);
}
-int FakeVimHandler::Private::indentText(const Range &range, QChar typedChar)
+void FakeVimHandler::Private::indentText(const Range &range, QChar typedChar)
{
int beginLine = lineForPosition(range.beginPos);
int endLine = lineForPosition(range.endPos);
if (beginLine > endLine)
qSwap(beginLine, endLine);
- int amount = 0;
- // lineForPosition has returned 1-based line numbers
- emit q->indentRegion(&amount, beginLine - 1, endLine - 1, typedChar);
- fixMarks(firstPositionInLine(beginLine), amount);
+ // LineForPosition has returned 1-based line numbers.
+ emit q->indentRegion(beginLine - 1, endLine - 1, typedChar);
if (beginLine != endLine)
showBlackMessage("MARKS ARE OFF NOW");
- return amount;
}
bool FakeVimHandler::Private::isElectricCharacter(QChar c) const
if (hasConfig(ConfigSmartIndent)) {
Range range(m_tc.block().position(), m_tc.block().position());
- m_justAutoIndented = indentText(range, QLatin1Char('\n'));
+ const int oldSize = m_tc.block().text().size();
+ indentText(range, QLatin1Char('\n'));
+ m_justAutoIndented = m_tc.block().text().size() - oldSize;
} else {
QTextBlock block = goingDown ? m_tc.block().previous() : m_tc.block().next();
QString text = block.text();
void FakeVimHandler::Private::selectBlockTextObject(bool inner, char left, char right)
{
- Q_UNUSED(inner);
- Q_UNUSED(left);
- Q_UNUSED(right);
+ QTextDocument *doc = m_tc.document();
+ QString sleft = QString(QLatin1Char(left));
+ QString sright = QString(QLatin1Char(right));
+ QTextCursor tc2 = doc->find(sright, m_tc);
+ if (tc2.isNull())
+ return;
+ QTextCursor tc1 = doc->find(sleft, m_tc, QTextDocument::FindBackward);
+ if (tc1.isNull())
+ return;
+ const int p1 = tc1.position() + inner - sleft.size();
+ const int p2 = tc2.position() - inner - sright.size();
+ setMark('>', p1);
+ m_anchor = p2;
+ setMark('<', p2);
+ setPosition(p1);
+ m_movetype = MoveInclusive;
}
void FakeVimHandler::Private::selectQuotedStringTextObject(bool inner, int type)
return d->tabExpand(n);
}
+void FakeVimHandler::fixMarks(int positionAction, int positionChange)
+{
+ d->fixMarks(positionAction, positionChange);
+}
} // namespace Internal
} // namespace FakeVim
int physicalIndentation(const QString &line) const;
int logicalIndentation(const QString &line) const;
QString tabExpand(int n) const;
+ void fixMarks(int positionAction, int positionChange);
signals:
void commandBufferChanged(const QString &msg);
void writeAllRequested(QString *error);
void moveToMatchingParenthesis(bool *moved, bool *forward, QTextCursor *cursor);
void checkForElectricCharacter(bool *result, QChar c);
- void indentRegion(int *amount, int beginLine, int endLine, QChar typedChar);
+ void indentRegion(int beginLine, int endLine, QChar typedChar);
void completionRequested();
void windowCommandRequested(int key);
void findRequested(bool reverse);
#include <cpptools/cpptoolsconstants.h>
-#include <indenter.h>
-
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtCore/QtPlugin>
void changeSelection(const QList<QTextEdit::ExtraSelection> &selections);
void moveToMatchingParenthesis(bool *moved, bool *forward, QTextCursor *cursor);
void checkForElectricCharacter(bool *result, QChar c);
- void indentRegion(int *amount, int beginLine, int endLine, QChar typedChar);
+ void indentRegion(int beginLine, int endLine, QChar typedChar);
void handleExCommand(bool *handled, const ExCommand &cmd);
void handleDelayedQuitAll(bool forced);
void FakeVimPluginPrivate::windowCommand(int key)
{
- #define control(n) (256 + n)
+# define control(n) (256 + n)
QString code;
switch (key) {
case 'c': case 'C': case control('c'):
code = Core::Constants::GOTO_OTHER_SPLIT;
break;
}
- #undef control
+# undef control
//qDebug() << "RUNNING WINDOW COMMAND: " << key << code;
if (code.isEmpty()) {
//qDebug() << "UNKNOWN WINDOWS COMMAND: " << key;
this, SLOT(changeSelection(QList<QTextEdit::ExtraSelection>)));
connect(handler, SIGNAL(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)),
this, SLOT(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)));
- connect(handler, SIGNAL(indentRegion(int*,int,int,QChar)),
- this, SLOT(indentRegion(int*,int,int,QChar)));
+ connect(handler, SIGNAL(indentRegion(int,int,QChar)),
+ this, SLOT(indentRegion(int,int,QChar)));
connect(handler, SIGNAL(checkForElectricCharacter(bool*,QChar)),
this, SLOT(checkForElectricCharacter(bool*,QChar)));
connect(handler, SIGNAL(completionRequested()),
}
}
-void FakeVimPluginPrivate::indentRegion(int *amount, int beginLine, int endLine,
+void FakeVimPluginPrivate::indentRegion(int beginLine, int endLine,
QChar typedChar)
{
FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
if (!bt)
return;
- TextEditor::TabSettings tabSettings;
+ const TextEditor::TabSettings oldTabSettings = bt->tabSettings();
+
+ TabSettings tabSettings;
tabSettings.m_indentSize = theFakeVimSetting(ConfigShiftWidth)->value().toInt();
tabSettings.m_tabSize = theFakeVimSetting(ConfigTabStop)->value().toInt();
tabSettings.m_spacesForTabs = theFakeVimSetting(ConfigExpandTab)->value().toBool();
- typedef SharedTools::Indenter<TextEditor::TextBlockIterator> Indenter;
- Indenter &indenter = Indenter::instance();
- indenter.setIndentSize(tabSettings.m_indentSize);
- indenter.setTabSize(tabSettings.m_tabSize);
-
- const QTextDocument *doc = bt->document();
- const TextEditor::TextBlockIterator docStart(doc->begin());
- QTextBlock cur = doc->findBlockByNumber(beginLine);
+ bt->setTabSettings(tabSettings);
+
+ QTextDocument *doc = bt->document();
+ QTextBlock startBlock = doc->findBlockByNumber(beginLine);
+
+ // Record line lenghts for mark adjustments
+ QVector<int> lineLengths(endLine - beginLine + 1);
+ QTextBlock block = startBlock;
+
for (int i = beginLine; i <= endLine; ++i) {
- if (typedChar == 0 && cur.text().simplified().isEmpty()) {
+ lineLengths[i - beginLine] = block.text().length();
+ if (typedChar == 0 && block.text().simplified().isEmpty()) {
// clear empty lines
- *amount = 0;
- QTextCursor cursor(cur);
+ QTextCursor cursor(block);
while (!cursor.atBlockEnd())
cursor.deleteChar();
} else {
- const TextEditor::TextBlockIterator current(cur);
- const TextEditor::TextBlockIterator next(cur.next());
- *amount = indenter.indentForBottomLine(current, docStart, next, typedChar);
- tabSettings.indentLine(cur, *amount);
+ bt->indentBlock(doc, block, typedChar);
}
- cur = cur.next();
+ block = block.next();
}
+
+ // Adjust marks.
+ block = startBlock;
+ for (int i = beginLine; i <= endLine; ++i) {
+ const int amount = block.text().length() - lineLengths[i - beginLine];
+ handler->fixMarks(block.position(), amount);
+ block = block.next();
+ }
+
+ bt->setTabSettings(oldTabSettings);
}
void FakeVimPluginPrivate::quitFakeVim()
-<plugin name="Find" version="2.0.80" compatVersion="2.0.80">
+<plugin name="Find" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Provides the find widget and the hooks for find implementations.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
</dependencyList>
</plugin>
#include "basetextfind.h"
#include <utils/qtcassert.h>
+#include <utils/filesearch.h>
#include <QtGui/QTextBlock>
#include <QtGui/QPlainTextEdit>
return found ? Found : NotFound;
}
-namespace {
- QString expandRegExpReplacement(const QString &replaceText, const QRegExp ®exp)
- {
- QString result;
- for (int i = 0; i < replaceText.length(); ++i) {
- QChar c = replaceText.at(i);
- if (c == QLatin1Char('\\') && i < replaceText.length() - 1) {
- c = replaceText.at(++i);
- if (c == QLatin1Char('\\')) {
- result += QLatin1Char('\\');
- } else if (c == QLatin1Char('&')) {
- result += QLatin1Char('&');
- } else if (c.isDigit()) {
- int index = c.unicode()-'1';
- if (index < regexp.numCaptures()) {
- result += regexp.cap(index+1);
- } else {
- result += QLatin1Char('\\');
- result += c;
- }
- } else {
- result += QLatin1Char('\\');
- result += c;
- }
- } else if (c == QLatin1Char('&')) {
- result += regexp.cap(0);
- } else {
- result += c;
- }
- }
- return result;
- }
-}
-
bool BaseTextFind::replaceStep(const QString &before, const QString &after,
IFindSupport::FindFlags findFlags)
{
usesRegExp ? QRegExp::RegExp : QRegExp::FixedString);
if (regexp.exactMatch(cursor.selectedText())) {
- QString realAfter = usesRegExp ? expandRegExpReplacement(after, regexp) : after;
+ QString realAfter = usesRegExp ? Utils::expandRegExpReplacement(after, regexp.capturedTexts()) : after;
int start = cursor.selectionStart();
cursor.insertText(realAfter);
if ((findFlags&IFindSupport::FindBackward) != 0)
editCursor.setPosition(found.selectionStart());
editCursor.setPosition(found.selectionEnd(), QTextCursor::KeepAnchor);
regexp.exactMatch(found.selectedText());
- QString realAfter = usesRegExp ? expandRegExpReplacement(after, regexp) : after;
+ QString realAfter = usesRegExp ? Utils::expandRegExpReplacement(after, regexp.capturedTexts()) : after;
editCursor.insertText(realAfter);
found = findOne(regexp, editCursor, IFindSupport::textDocumentFlagsForFindFlags(findFlags));
}
}
else {
clearFindSupport();
- m_currentFind = 0;
}
}
}
void CurrentDocumentFind::candidateAggregationChanged()
{
- if (m_candidateWidget && m_candidateWidget!=m_currentWidget) {
+ if (m_candidateWidget && m_candidateWidget != m_currentWidget) {
m_candidateFind = Aggregation::query<IFindSupport>(m_candidateWidget);
emit candidateChanged();
}
namespace Find {
+ class WideEnoughLineEdit : public QLineEdit {
+ Q_OBJECT
+ public:
+ WideEnoughLineEdit(QWidget *parent):QLineEdit(parent){
+ connect(this, SIGNAL(textChanged(QString)),
+ this, SLOT(updateGeometry()));
+ }
+ ~WideEnoughLineEdit(){}
+ QSize sizeHint() const {
+ QSize sh = QLineEdit::minimumSizeHint();
+ sh.rwidth() += qMax(25 * fontMetrics().width(QLatin1Char('x')),
+ fontMetrics().width(text()));
+ return sh;
+ }
+ public slots:
+ void updateGeometry() { QLineEdit::updateGeometry(); }
+ };
+
+
struct SearchResultWindowPrivate {
SearchResultWindowPrivate();
d->m_replaceLabel = new QLabel(tr("Replace with:"), d->m_widget);
d->m_replaceLabel->setContentsMargins(12, 0, 5, 0);
- d->m_replaceTextEdit = new QLineEdit(d->m_widget);
+ d->m_replaceTextEdit = new WideEnoughLineEdit(d->m_widget);
d->m_replaceButton = new QToolButton(d->m_widget);
d->m_replaceButton->setToolTip(tr("Replace all occurrences"));
d->m_replaceButton->setText(tr("Replace"));
} // namespace Find
+
+#include "searchresultwindow.moc"
-<plugin name="GenericProjectManager" version="2.0.80" compatVersion="2.0.80">
+<plugin name="GenericProjectManager" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Generic support</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
- <dependency name="CppTools" version="2.0.80"/>
- <dependency name="CppEditor" version="2.0.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
+ <dependency name="CppTools" version="2.1.80"/>
+ <dependency name="CppEditor" version="2.1.80"/>
</dependencyList>
</plugin>
return false;
}
+void GenericProjectFile::rename(const QString &newName)
+{
+ // Can't happen
+ Q_UNUSED(newName);
+ Q_ASSERT(false);
+}
+
Core::IFile::ReloadBehavior GenericProjectFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
{
Q_UNUSED(state)
virtual bool isModified() const;
virtual bool isReadOnly() const;
virtual bool isSaveAsAllowed() const;
+ virtual void rename(const QString &newName);
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
void reload(ReloadFlag flag, ChangeType type);
return true;
}
-QList<ProjectExplorer::ProjectNode::ProjectAction> GenericProjectNode::supportedActions() const
+QList<ProjectExplorer::ProjectNode::ProjectAction> GenericProjectNode::supportedActions(Node *node) const
{
+ Q_UNUSED(node);
return QList<ProjectAction>()
<< AddFile
<< RemoveFile;
virtual bool hasBuildTargets() const;
- virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions() const;
+ virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions(Node *node) const;
virtual bool addSubProjects(const QStringList &proFilePaths);
virtual bool removeSubProjects(const QStringList &proFilePaths);
-<plugin name="ScmGit" version="2.0.80" compatVersion="2.0.80">
+<plugin name="ScmGit" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Git integration.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
- <dependency name="Core" version="2.0.80"/>
- <dependency name="VCSBase" version="2.0.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
+ <dependency name="Core" version="2.1.80"/>
+ <dependency name="VCSBase" version="2.1.80"/>
</dependencyList>
</plugin>
args << QLatin1String("clone") << repository() << checkoutDir;
const QString binary = args.front();
args.pop_front();
- VCSBase::AbstractCheckoutJob *job = new VCSBase::ProcessCheckoutJob(binary, args, workingDirectory,
- client->processEnvironment());
+ VCSBase::AbstractCheckoutJob *job =
+ new VCSBase::ProcessCheckoutJob(binary, args, workingDirectory,
+ client->processEnvironment());
return QSharedPointer<VCSBase::AbstractCheckoutJob>(job);
}
return GitClient::tr("Unable to parse the file output.");
}
-// Format a command for the status window
-static QString formatCommand(const QString &binary, const QStringList &args)
-{
- //: Executing: <executable> <arguments>
- return GitClient::tr("Executing: %1 %2\n").arg(binary, args.join(QString(QLatin1Char(' '))));
-}
-
// ---------------- GitClient
const char *GitClient::stashNamePrefix = "stash@{";
if (unstagedFileNames.empty() && stagedFileNames.empty()) {
QStringList arguments(commonDiffArgs);
arguments << diffArgs;
- outputWindow()->appendCommand(formatCommand(binary, arguments));
+ outputWindow()->appendCommand(workingDirectory, binary, arguments);
command->addJob(arguments, m_settings.timeoutSeconds);
} else {
// Files diff.
if (!unstagedFileNames.empty()) {
QStringList arguments(commonDiffArgs);
arguments << QLatin1String("--") << unstagedFileNames;
- outputWindow()->appendCommand(formatCommand(binary, arguments));
+ outputWindow()->appendCommand(workingDirectory, binary, arguments);
command->addJob(arguments, m_settings.timeoutSeconds);
}
if (!stagedFileNames.empty()) {
QStringList arguments(commonDiffArgs);
arguments << QLatin1String("--cached") << diffArgs << QLatin1String("--") << stagedFileNames;
- outputWindow()->appendCommand(formatCommand(binary, arguments));
+ outputWindow()->appendCommand(workingDirectory, binary, arguments);
command->addJob(arguments, m_settings.timeoutSeconds);
}
}
QByteArray errorText;
QStringList arguments;
arguments << QLatin1String("checkout") << branch;
- const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, arguments, &outputText, &errorText);
const QString output = commandOutputFromLocal8Bit(outputText);
outputWindow()->append(output);
if (!rc) {
if (intendToAdd)
arguments << QLatin1String("--intent-to-add");
arguments.append(files);
- const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, arguments, &outputText, &errorText);
if (!rc) {
const QString errorMessage = tr("Unable to add %n file(s) to %1: %2", 0, files.size()).
arg(workingDirectory, commandOutputFromLocal8Bit(errorText));
if (force)
arguments << QLatin1String("--force");
arguments.append(files);
- const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, arguments, &outputText, &errorText);
if (!rc) {
const QString errorMessage = tr("Unable to remove %n file(s) from %1: %2", 0, files.size()).
arg(workingDirectory, commandOutputFromLocal8Bit(errorText));
return rc;
}
+bool GitClient::synchronousMove(const QString &workingDirectory,
+ const QString &from,
+ const QString &to)
+{
+ if (Git::Constants::debug)
+ qDebug() << Q_FUNC_INFO << workingDirectory << from << to;
+ QByteArray outputText;
+ QByteArray errorText;
+ QStringList arguments;
+ arguments << QLatin1String("mv");
+ arguments << (from);
+ arguments << (to);
+ const bool rc = fullySynchronousGit(workingDirectory, arguments, &outputText, &errorText);
+ if (!rc) {
+ const QString errorMessage = tr("Unable to move from %1 to %2: %3").
+ arg(from, to, commandOutputFromLocal8Bit(errorText));
+ outputWindow()->appendError(errorMessage);
+ }
+ return rc;
+}
+
bool GitClient::synchronousReset(const QString &workingDirectory,
const QStringList &files,
QString *errorMessage)
} else {
arguments << QLatin1String("HEAD") << QLatin1String("--") << files;
}
- const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, arguments, &outputText, &errorText);
const QString output = commandOutputFromLocal8Bit(outputText);
outputWindow()->append(output);
// Note that git exits with 1 even if the operation is successful
QByteArray outputText;
QByteArray errorText;
const QStringList arguments(QLatin1String("init"));
- const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, arguments, &outputText, &errorText);
// '[Re]Initialized...'
outputWindow()->append(commandOutputFromLocal8Bit(outputText));
if (!rc)
QByteArray errorText;
QStringList arguments;
arguments << QLatin1String("checkout") << revision << QLatin1String("--") << files;
- const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, arguments, &outputText, &errorText);
if (!rc) {
const QString fileArg = files.join(QLatin1String(", "));
//: Meaning of the arguments: %1: revision, %2: files, %3: repository,
arguments.append(QLatin1String("--"));
arguments.append(files);
}
- const bool rc = synchronousGit(workingDirectory, arguments, &outputTextData, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, arguments, &outputTextData, &errorText);
if (!rc) {
*errorMessage = msgParentRevisionFailed(workingDirectory, revision, commandOutputFromLocal8Bit(errorText));
return false;
revision->clear();
arguments << QLatin1String("log") << QLatin1String(noColorOption)
<< QLatin1String("--max-count=1") << QLatin1String("--pretty=format:%H");
- if (!synchronousGit(workingDirectory, arguments, &outputTextData, &errorText)) {
+ if (!fullySynchronousGit(workingDirectory, arguments, &outputTextData, &errorText)) {
errorMessage = tr("Unable to retrieve top revision of %1: %2").arg(workingDirectory, commandOutputFromLocal8Bit(errorText));
break;
}
branch->clear();
arguments.clear();
arguments << QLatin1String("branch") << QLatin1String(noColorOption);
- if (!synchronousGit(workingDirectory, arguments, &outputTextData, &errorText)) {
+ if (!fullySynchronousGit(workingDirectory, arguments, &outputTextData, &errorText)) {
errorMessage = msgCannotDetermineBranch(workingDirectory, commandOutputFromLocal8Bit(errorText));
break;
}
arguments << QLatin1String("log") << QLatin1String(GitClient::noColorOption)
<< (QLatin1String("--pretty=format:") + format)
<< QLatin1String("--max-count=1") << revision;
- const bool rc = synchronousGit(workingDirectory, arguments, &outputTextData, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, arguments, &outputTextData, &errorText);
if (!rc) {
*errorMessage = tr("Unable to describe revision %1 in %2: %3").arg(revision, workingDirectory, commandOutputFromLocal8Bit(errorText));
return false;
arguments << QLatin1String("stash");
if (!message.isEmpty())
arguments << QLatin1String("save") << message;
- const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, arguments, &outputText, &errorText);
if (!rc) {
const QString msg = tr("Unable stash in %1: %2").arg(workingDirectory, commandOutputFromLocal8Bit(errorText));
if (errorMessage) {
branchArgs.push_front(QLatin1String("branch"));
QByteArray outputText;
QByteArray errorText;
- const bool rc = synchronousGit(workingDirectory, branchArgs, &outputText, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, branchArgs, &outputText, &errorText);
if (!rc) {
*errorMessage = tr("Unable to run a 'git branch' command in %1: %2").arg(workingDirectory, commandOutputFromLocal8Bit(errorText));
return false;
args << QLatin1String(noColorOption) << id;
QByteArray outputText;
QByteArray errorText;
- const bool rc = synchronousGit(workingDirectory, args, &outputText, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, args, &outputText, &errorText);
if (!rc) {
*errorMessage = tr("Unable to run 'git show' in %1: %2").arg(workingDirectory, commandOutputFromLocal8Bit(errorText));
return false;
args << QLatin1String("clean") << QLatin1String("--dry-run") << QLatin1String("-dxf");
QByteArray outputText;
QByteArray errorText;
- const bool rc = synchronousGit(workingDirectory, args, &outputText, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, args, &outputText, &errorText);
if (!rc) {
*errorMessage = tr("Unable to run 'git clean' in %1: %2").arg(workingDirectory, commandOutputFromLocal8Bit(errorText));
return false;
args << QLatin1String("apply") << QLatin1String("--whitespace=fix") << file;
QByteArray outputText;
QByteArray errorText;
- const bool rc = synchronousGit(workingDirectory, args, &outputText, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, args, &outputText, &errorText);
if (rc) {
if (!errorText.isEmpty())
*errorMessage = tr("There were warnings while applying %1 to %2:\n%3").arg(file, workingDirectory, commandOutputFromLocal8Bit(errorText));
VCSBase::VCSBaseEditor* editor,
bool outputToWindow,
GitCommand::TerminationReportMode tm,
- int editorLineNumber)
+ int editorLineNumber,
+ bool unixTerminalDisabled)
{
- outputWindow()->appendCommand(formatCommand(QLatin1String(Constants::GIT_BINARY), arguments));
+ outputWindow()->appendCommand(workingDirectory, QLatin1String(Constants::GIT_BINARY), arguments);
GitCommand *command = createCommand(workingDirectory, editor, outputToWindow, editorLineNumber);
command->addJob(arguments, m_settings.timeoutSeconds);
command->setTerminationReportMode(tm);
+ command->setUnixTerminalDisabled(unixTerminalDisabled);
command->execute();
return command;
}
#endif
}
-QStringList GitClient::processEnvironment() const
+QProcessEnvironment GitClient::processEnvironment() const
{
- ProjectExplorer::Environment environment = ProjectExplorer::Environment::systemEnvironment();
+ QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
if (m_settings.adoptPath)
- environment.set(QLatin1String("PATH"), m_settings.path);
- // git svn runs perl which barfs at non-C locales.
- environment.set(QLatin1String("LANG"), QString(QLatin1Char('C')));
- return environment.toStringList();
+ environment.insert(QLatin1String("PATH"), m_settings.path);
+ // Set up SSH and C locale (required by git using perl).
+ VCSBase::VCSBasePlugin::setProcessEnvironment(&environment);
+ return environment;
}
-bool GitClient::synchronousGit(const QString &workingDirectory,
+// Synchronous git execution using Utils::SynchronousProcess, with
+// log windows updating.
+Utils::SynchronousProcessResponse
+ GitClient::synchronousGit(const QString &workingDirectory,
+ const QStringList &gitArguments,
+ unsigned flags,
+ QTextCodec *stdOutCodec)
+{
+ if (Git::Constants::debug)
+ qDebug() << "synchronousGit" << workingDirectory << gitArguments;
+ QStringList args = binary(); // "cmd /c git" on Windows
+ const QString executable = args.front();
+ args.pop_front();
+ args.append(gitArguments);
+ return VCSBase::VCSBasePlugin::runVCS(workingDirectory, executable, args,
+ m_settings.timeoutSeconds * 1000,
+ flags, stdOutCodec);
+}
+
+bool GitClient::fullySynchronousGit(const QString &workingDirectory,
const QStringList &gitArguments,
QByteArray* outputText,
QByteArray* errorText,
bool logCommandToWindow)
{
if (Git::Constants::debug)
- qDebug() << "synchronousGit" << workingDirectory << gitArguments;
+ qDebug() << "fullySynchronousGit" << workingDirectory << gitArguments;
if (logCommandToWindow)
- outputWindow()->appendCommand(formatCommand(m_binaryPath, gitArguments));
+ outputWindow()->appendCommand(workingDirectory, m_binaryPath, gitArguments);
QProcess process;
process.setWorkingDirectory(workingDirectory);
- process.setEnvironment(processEnvironment());
+ process.setProcessEnvironment(processEnvironment());
QStringList args = binary(); // "cmd /c git" on Windows
const QString executable = args.front();
}
if (!Utils::SynchronousProcess::readDataFromProcess(process, m_settings.timeoutSeconds * 1000,
- outputText, errorText)) {
- *errorText->append(GitCommand::msgTimeout(m_settings.timeoutSeconds).toLocal8Bit());
+ outputText, errorText, true)) {
+ errorText->append(GitCommand::msgTimeout(m_settings.timeoutSeconds).toLocal8Bit());
Utils::SynchronousProcess::stopProcess(process);
return false;
}
QStringList statusArgs(QLatin1String("status"));
if (untracked)
statusArgs << QLatin1String("-u");
- const bool statusRc = synchronousGit(workingDirectory, statusArgs, &outputText, &errorText);
+ const bool statusRc = fullySynchronousGit(workingDirectory, statusArgs, &outputText, &errorText);
GitCommand::removeColorCodes(&outputText);
if (output)
*output = commandOutputFromLocal8Bit(outputText);
return StatusChanged;
}
+void GitClient::launchGitK(const QString &workingDirectory)
+{
+ VCSBase::VCSBaseOutputWindow *outwin = VCSBase::VCSBaseOutputWindow::instance();
+ // Locate git in (potentially) custom path. m_binaryPath can be absolute,
+ // which will be handled correctly.
+ QTC_ASSERT(!m_binaryPath.isEmpty(), return);
+ const QString gitBinary = QLatin1String(Constants::GIT_BINARY);
+ const QProcessEnvironment env = processEnvironment();
+ const QString path = env.value(QLatin1String("PATH"));
+ const QString fullGitBinary = Utils::SynchronousProcess::locateBinary(path, m_binaryPath);
+ if (fullGitBinary.isEmpty()) {
+ outwin->appendError(tr("Cannot locate %1.").arg(gitBinary));
+ return;
+ }
+ const QString gitBinDirectory = QFileInfo(fullGitBinary).absolutePath();
+#ifdef Q_OS_WIN
+ // Launch 'wish' shell from git binary directory with the gitk located there
+ const QString binary = gitBinDirectory + QLatin1String("/wish");
+ const QStringList arguments(gitBinDirectory + QLatin1String("/gitk"));
+#else
+ // Simple: Run gitk from binary path
+ const QString binary = gitBinDirectory + QLatin1String("/gitk");
+ const QStringList arguments;
+#endif
+ outwin->appendCommand(workingDirectory, binary, arguments);
+ // This should always use QProcess::startDetached (as not to kill
+ // the child), but that does not have an environment parameter.
+ bool success = false;
+ if (m_settings.adoptPath) {
+ QProcess *process = new QProcess(this);
+ process->setWorkingDirectory(workingDirectory);
+ process->setProcessEnvironment(env);
+ process->start(binary, arguments);
+ success = process->waitForStarted();
+ if (success) {
+ connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
+ } else {
+ delete process;
+ }
+ } else {
+ success = QProcess::startDetached(binary, arguments, workingDirectory);
+ }
+ if (!success)
+ outwin->appendError(tr("Unable to launch %1.").arg(binary));
+}
+
bool GitClient::getCommitData(const QString &workingDirectory,
QString *commitTemplate,
CommitData *d,
QByteArray outputText;
QByteArray errorText;
- const bool rc = synchronousGit(repositoryDirectory, args, &outputText, &errorText);
+ const bool rc = fullySynchronousGit(repositoryDirectory, args, &outputText, &errorText);
if (rc) {
outputWindow()->append(tr("Committed %n file(s).\n", 0, checkedFiles.size()));
} else {
}
}
-void GitClient::pull(const QString &workingDirectory)
+bool GitClient::synchronousPull(const QString &workingDirectory)
{
- pull(workingDirectory, m_settings.pullRebase);
+ return synchronousPull(workingDirectory, m_settings.pullRebase);
}
-void GitClient::pull(const QString &workingDirectory, bool rebase)
+bool GitClient::synchronousPull(const QString &workingDirectory, bool rebase)
{
QStringList arguments(QLatin1String("pull"));
if (rebase)
arguments << QLatin1String("--rebase");
- GitCommand *cmd = executeGit(workingDirectory, arguments, 0, true, GitCommand::ReportStderr);
- connectRepositoryChanged(workingDirectory, cmd);
- // Need to clean up if something goes wrong
- if (rebase) {
- cmd->setCookie(QVariant(workingDirectory));
- connect(cmd, SIGNAL(finished(bool,int,QVariant)), this, SLOT(slotPullRebaseFinished(bool,int,QVariant)),
- Qt::QueuedConnection);
+ // Disable UNIX terminals to suppress SSH prompting.
+ const unsigned flags = VCSBase::VCSBasePlugin::SshPasswordPrompt|VCSBase::VCSBasePlugin::ShowStdOutInLogWindow
+ |VCSBase::VCSBasePlugin::ShowSuccessMessage;
+ const Utils::SynchronousProcessResponse resp = synchronousGit(workingDirectory, arguments, flags);
+ // Notify about changed files or abort the rebase.
+ const bool ok = resp.result == Utils::SynchronousProcessResponse::Finished;
+ if (ok) {
+ GitPlugin::instance()->gitVersionControl()->emitRepositoryChanged(workingDirectory);
+ } else {
+ if (rebase)
+ syncAbortPullRebase(workingDirectory);
}
+ return ok;
}
-void GitClient::slotPullRebaseFinished(bool ok, int exitCode, const QVariant &cookie)
+void GitClient::syncAbortPullRebase(const QString &workingDir)
{
- if (ok && exitCode == 0)
- return;
// Abort rebase to clean if something goes wrong
VCSBase::VCSBaseOutputWindow *outwin = VCSBase::VCSBaseOutputWindow::instance();
outwin->appendError(tr("The command 'git pull --rebase' failed, aborting rebase."));
- const QString workingDir = cookie.toString();
QStringList arguments;
arguments << QLatin1String("rebase") << QLatin1String("--abort");
QByteArray stdOut;
QByteArray stdErr;
- const bool rc = synchronousGit(workingDir, arguments, &stdOut, &stdErr, true);
+ const bool rc = fullySynchronousGit(workingDir, arguments, &stdOut, &stdErr, true);
outwin->append(commandOutputFromLocal8Bit(stdOut));
if (!rc)
outwin->appendError(commandOutputFromLocal8Bit(stdErr));
}
// Subversion: git svn
-void GitClient::subversionFetch(const QString &workingDirectory)
+void GitClient::synchronousSubversionFetch(const QString &workingDirectory)
{
QStringList args;
args << QLatin1String("svn") << QLatin1String("fetch");
- GitCommand *cmd = executeGit(workingDirectory, args, 0, true, GitCommand::ReportStderr);
- connectRepositoryChanged(workingDirectory, cmd);
+ // Disable UNIX terminals to suppress SSH prompting.
+ const unsigned flags = VCSBase::VCSBasePlugin::SshPasswordPrompt|VCSBase::VCSBasePlugin::ShowStdOutInLogWindow
+ |VCSBase::VCSBasePlugin::ShowSuccessMessage;
+ const Utils::SynchronousProcessResponse resp = synchronousGit(workingDirectory, args, flags);
+ // Notify about changes.
+ if (resp.result == Utils::SynchronousProcessResponse::Finished)
+ GitPlugin::instance()->gitVersionControl()->emitRepositoryChanged(workingDirectory);
}
void GitClient::subversionLog(const QString &workingDirectory)
executeGit(workingDirectory, arguments, editor);
}
-void GitClient::push(const QString &workingDirectory)
+bool GitClient::synchronousPush(const QString &workingDirectory)
{
- executeGit(workingDirectory, QStringList(QLatin1String("push")), 0, true, GitCommand::ReportStderr);
+ // Disable UNIX terminals to suppress SSH prompting.
+ const unsigned flags = VCSBase::VCSBasePlugin::SshPasswordPrompt|VCSBase::VCSBasePlugin::ShowStdOutInLogWindow
+ |VCSBase::VCSBasePlugin::ShowSuccessMessage;
+ const Utils::SynchronousProcessResponse resp =
+ synchronousGit(workingDirectory, QStringList(QLatin1String("push")), flags);
+ return resp.result == Utils::SynchronousProcessResponse::Finished;
}
QString GitClient::msgNoChangedFiles()
}
QByteArray outputText;
QByteArray errorText;
- const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, arguments, &outputText, &errorText);
if (!rc) {
const QString stdErr = commandOutputFromLocal8Bit(errorText);
const QString msg = branch.isEmpty() ?
}
QByteArray outputText;
QByteArray errorText;
- const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, arguments, &outputText, &errorText);
if (!rc) {
const QString stdErr = commandOutputFromLocal8Bit(errorText);
const QString msg = stash.isEmpty() ?
arguments << QLatin1String("list") << QLatin1String(noColorOption);
QByteArray outputText;
QByteArray errorText;
- const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
+ const bool rc = fullySynchronousGit(workingDirectory, arguments, &outputText, &errorText);
if (!rc) {
const QString msg = tr("Unable retrieve stash list of %1: %2").arg(workingDirectory, commandOutputFromLocal8Bit(errorText));
if (errorMessage) {
QByteArray outputText;
QByteArray errorText;
- if (synchronousGit(workingDirectory, arguments, &outputText, &errorText, false))
+ if (fullySynchronousGit(workingDirectory, arguments, &outputText, &errorText, false))
return commandOutputFromLocal8Bit(outputText);
return QString();
}
{
if (s != m_settings) {
m_settings = s;
- if (QSettings *s = m_core->settings())
- m_settings.toSettings(s);
+ if (QSettings *coreSettings = m_core->settings())
+ m_settings.toSettings(coreSettings);
m_binaryPath = m_settings.gitBinaryPath();
m_cachedGitVersion = 0u;
m_hasCachedGitVersion = false;
// run git --version
QByteArray outputText;
QByteArray errorText;
- const bool rc = synchronousGit(QString(), QStringList("--version"), &outputText, &errorText);
+ const bool rc = fullySynchronousGit(QString(), QStringList("--version"), &outputText, &errorText);
if (!rc) {
const QString msg = tr("Unable to determine git version: %1").arg(commandOutputFromLocal8Bit(errorText));
if (errorMessage) {
class QErrorMessage;
class QSignalMapper;
class QDebug;
+class QProcessEnvironment;
QT_END_NAMESPACE
namespace Core {
class VCSBaseEditor;
}
+namespace Utils {
+ struct SynchronousProcessResponse;
+}
+
namespace Git {
namespace Internal {
bool synchronousDelete(const QString &workingDirectory,
bool force,
const QStringList &files);
+ bool synchronousMove(const QString &workingDirectory,
+ const QString &from,
+ const QString &to);
bool synchronousReset(const QString &workingDirectory,
const QStringList &files = QStringList(),
QString *errorMessage = 0);
unsigned gitVersion(bool silent, QString *errorMessage = 0);
QString gitVersionString(bool silent, QString *errorMessage = 0);
- void pull(const QString &workingDirectory);
- void push(const QString &workingDirectory);
+ bool synchronousPull(const QString &workingDirectory);
+ bool synchronousPush(const QString &workingDirectory);
// git svn support (asynchronous).
- void subversionFetch(const QString &workingDirectory);
+ void synchronousSubversionFetch(const QString &workingDirectory);
void subversionLog(const QString &workingDirectory);
void stashPop(const QString &workingDirectory);
QString *errorMessage = 0,
bool *onBranch = 0);
+ void launchGitK(const QString &workingDirectory);
+
GitSettings settings() const;
void setSettings(const GitSettings &s);
QStringList binary() const; // Executable + basic arguments
- QStringList processEnvironment() const;
+ QProcessEnvironment processEnvironment() const;
static QString msgNoChangedFiles();
private slots:
void slotBlameRevisionRequested(const QString &source, QString change, int lineNumber);
- void slotPullRebaseFinished(bool ok, int exitCode, const QVariant &cookie);
private:
VCSBase::VCSBaseEditor *createVCSEditor(const QString &kind,
VCSBase::VCSBaseEditor* editor = 0,
bool outputToWindow = false,
GitCommand::TerminationReportMode tm = GitCommand::NoReport,
- int editorLineNumber = -1);
+ int editorLineNumber = -1,
+ bool unixTerminalDisabled = false);
- bool synchronousGit(const QString &workingDirectory,
+ // Fully synchronous git execution (QProcess-based).
+ bool fullySynchronousGit(const QString &workingDirectory,
const QStringList &arguments,
QByteArray* outputText,
QByteArray* errorText,
bool logCommandToWindow = true);
+
+ // Synchronous git execution using Utils::SynchronousProcess, with
+ // log windows updating (using VCSBasePlugin::runVCS with flags).
+ inline Utils::SynchronousProcessResponse
+ synchronousGit(const QString &workingDirectory, const QStringList &arguments,
+ unsigned flags = 0, QTextCodec *outputCodec = 0);
+
// determine version as '(major << 16) + (minor << 8) + patch' or 0.
unsigned synchronousGitVersion(bool silent, QString *errorMessage = 0);
enum RevertResult { RevertOk, RevertUnchanged, RevertCanceled, RevertFailed };
RevertResult revertI(QStringList files, bool *isDirectory, QString *errorMessage);
void connectRepositoryChanged(const QString & repository, GitCommand *cmd);
- void pull(const QString &workingDirectory, bool rebase);
+ bool synchronousPull(const QString &workingDirectory, bool rebase);
+ void syncAbortPullRebase(const QString &workingDir);
const QString m_msgWait;
GitPlugin *m_plugin;
GitCommand::GitCommand(const QStringList &binary,
const QString &workingDirectory,
- const QStringList &environment,
+ const QProcessEnvironment&environment,
const QVariant &cookie) :
m_binaryPath(binary.front()),
m_basicArguments(binary),
m_workingDirectory(workingDirectory),
m_environment(environment),
m_cookie(cookie),
+ m_unixTerminalDisabled(false),
m_reportTerminationMode(NoReport)
{
m_basicArguments.pop_front();
m_reportTerminationMode = m;
}
+bool GitCommand::unixTerminalDisabled() const
+{
+ return m_unixTerminalDisabled;
+}
+
+void GitCommand::setUnixTerminalDisabled(bool e)
+{
+ m_unixTerminalDisabled = e;
+}
+
void GitCommand::addJob(const QStringList &arguments, int timeout)
{
m_jobs.push_back(Job(arguments, timeout));
void GitCommand::run()
{
if (Git::Constants::debug)
- qDebug() << "GitCommand::run" << m_workingDirectory << m_jobs.size();
- QProcess process;
+ qDebug() << "GitCommand::run" << m_workingDirectory << m_jobs.size()
+ << "terminal_disabled" << m_unixTerminalDisabled;
+
+ const unsigned processFlags = m_unixTerminalDisabled ?
+ unsigned(Utils::SynchronousProcess::UnixTerminalDisabled) :
+ unsigned(0);
+ const QSharedPointer<QProcess> process =
+ Utils::SynchronousProcess::createProcess(processFlags);
if (!m_workingDirectory.isEmpty())
- process.setWorkingDirectory(m_workingDirectory);
+ process->setWorkingDirectory(m_workingDirectory);
- process.setEnvironment(m_environment);
+ process->setProcessEnvironment(m_environment);
QByteArray stdOut;
QByteArray stdErr;
if (Git::Constants::debug)
qDebug() << "GitCommand::run" << j << '/' << count << m_jobs.at(j).arguments;
- process.start(m_binaryPath, m_basicArguments + m_jobs.at(j).arguments);
- if(!process.waitForStarted()) {
+ process->start(m_binaryPath, m_basicArguments + m_jobs.at(j).arguments);
+ if(!process->waitForStarted()) {
ok = false;
- error += QString::fromLatin1("Error: \"%1\" could not be started: %2").arg(m_binaryPath, process.errorString());
+ error += QString::fromLatin1("Error: \"%1\" could not be started: %2").arg(m_binaryPath, process->errorString());
break;
}
- process.closeWriteChannel();
+ process->closeWriteChannel();
const int timeOutSeconds = m_jobs.at(j).timeout;
- if (!Utils::SynchronousProcess::readDataFromProcess(process, timeOutSeconds * 1000,
- &stdOut, &stdErr)) {
- Utils::SynchronousProcess::stopProcess(process);
+ if (!Utils::SynchronousProcess::readDataFromProcess(*process, timeOutSeconds * 1000,
+ &stdOut, &stdErr, false)) {
+ Utils::SynchronousProcess::stopProcess(*process);
ok = false;
error += msgTimeout(timeOutSeconds);
break;
}
error += QString::fromLocal8Bit(stdErr);
- exitCode = process.exitCode();
+ exitCode = process->exitCode();
switch (m_reportTerminationMode) {
case NoReport:
break;
#include <QtCore/QObject>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
+#include <QtCore/QProcessEnvironment>
QT_BEGIN_NAMESPACE
class QProcess;
explicit GitCommand(const QStringList &binary,
const QString &workingDirectory,
- const QStringList &environment,
+ const QProcessEnvironment &environment,
const QVariant &cookie = QVariant());
TerminationReportMode reportTerminationMode() const;
void setTerminationReportMode(TerminationReportMode m);
+ // Disable Terminal on UNIX (see VCS SSH handling).
+ bool unixTerminalDisabled() const;
+ void setUnixTerminalDisabled(bool);
+
static QString msgTimeout(int seconds);
void setCookie(const QVariant &cookie);
const QString m_binaryPath;
QStringList m_basicArguments;
const QString m_workingDirectory;
- const QStringList m_environment;
+ const QProcessEnvironment m_environment;
QVariant m_cookie;
+ bool m_unixTerminalDisabled;
QList<Job> m_jobs;
TerminationReportMode m_reportTerminationMode;
tr("Clean Repository..."), QLatin1String("Git.CleanRepository"),
globalcontext, true, SLOT(cleanRepository()));
+ createRepositoryAction(actionManager, gitContainer,
+ tr("Launch gitk"), QLatin1String("Git.LaunchGitK"),
+ globalcontext, false, &GitClient::launchGitK);
+
gitContainer->addAction(createSeparator(actionManager, globalcontext, QLatin1String("Git.Sep.Global"), this));
ActionCommandPair actionCommand =
createRepositoryAction(actionManager, subversionMenu,
tr("Fetch"), QLatin1String("Git.Subversion.Fetch"),
- globalcontext, false, &GitClient::subversionFetch);
+ globalcontext, false, &GitClient::synchronousSubversionFetch);
if (0) {
const QList<QAction*> snapShotActions = createSnapShotTestActions();
case GitClient::StashUnchanged:
case GitClient::Stashed:
case GitClient::NotStashed:
- m_gitClient->pull(state.topLevel());
+ m_gitClient->synchronousPull(state.topLevel());
default:
break;
}
{
const VCSBase::VCSBasePluginState state = currentState();
QTC_ASSERT(state.hasTopLevel(), return)
- m_gitClient->push(state.topLevel());
+ m_gitClient->synchronousPush(state.topLevel());
}
// Retrieve member function of git client stored as user data of action
case DeleteOperation:
rc = true;
break;
+ case MoveOperation:
+ rc = true;
+ break;
case OpenOperation:
break;
case CreateRepositoryOperation:
return gitClient()->synchronousDelete(fi.absolutePath(), true, QStringList(fi.fileName()));
}
+bool GitVersionControl::vcsMove(const QString &from, const QString &to)
+{
+ const QFileInfo fromInfo(from);
+ const QFileInfo toInfo(to);
+ return gitClient()->synchronousMove(fromInfo.absolutePath(), fromInfo.absoluteFilePath(), toInfo.absoluteFilePath());
+}
+
bool GitVersionControl::vcsCreateRepository(const QString &directory)
{
return gitClient()->synchronousInit(directory);
&& gitClient()->synchronousStashRemove(topLevel, stashName);
}
-bool GitVersionControl::managesDirectory(const QString &directory) const
-{
- return !GitClient::findRepositoryForDirectory(directory).isEmpty();
-}
-
-QString GitVersionControl::findTopLevelForDirectory(const QString &directory) const
+bool GitVersionControl::managesDirectory(const QString &directory, QString *topLevel) const
{
- return GitClient::findRepositoryForDirectory(directory);
+ const QString topLevelFound = GitClient::findRepositoryForDirectory(directory);
+ if (topLevel)
+ *topLevel = topLevelFound;
+ return !topLevelFound.isEmpty();
}
bool GitVersionControl::vcsAnnotate(const QString &file, int line)
virtual QString displayName() const;
- bool managesDirectory(const QString &directory) const;
- virtual QString findTopLevelForDirectory(const QString &directory) const;
+ virtual bool managesDirectory(const QString &directory, QString *topLevel) const;
virtual bool supportsOperation(Operation operation) const;
virtual bool vcsOpen(const QString &fileName);
virtual bool vcsAdd(const QString &fileName);
virtual bool vcsDelete(const QString &filename);
+ virtual bool vcsMove(const QString &from, const QString &to);
virtual bool vcsCreateRepository(const QString &directory);
virtual QString vcsCreateSnapshot(const QString &topLevel);
virtual QStringList vcsSnapshots(const QString &topLevel);
-<plugin name="HelloWorld" version="2.0.80" compatVersion="2.0.80">
+<plugin name="HelloWorld" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Hello World sample plugin.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
</dependencyList>
</plugin>
-<plugin name="Help" version="2.0.80" compatVersion="2.0.80">
+<plugin name="Help" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Help system.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
- <dependency name="Find" version="2.0.80"/>
- <dependency name="Locator" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
+ <dependency name="Find" version="2.1.80"/>
+ <dependency name="Locator" version="2.1.80"/>
</dependencyList>
</plugin>
if (HelpViewer* viewer = currentHelpViewer()) {
initPrinter();
- QPrintDialog *dlg = new QPrintDialog(printer, this);
- dlg->setWindowTitle(tr("Print Document"));
+ QPrintDialog dlg(printer, this);
+ dlg.setWindowTitle(tr("Print Document"));
if (!viewer->selectedText().isEmpty())
- dlg->addEnabledOption(QAbstractPrintDialog::PrintSelection);
- dlg->addEnabledOption(QAbstractPrintDialog::PrintPageRange);
- dlg->addEnabledOption(QAbstractPrintDialog::PrintCollateCopies);
-
- if (dlg->exec() == QDialog::Accepted)
+ dlg.addEnabledOption(QAbstractPrintDialog::PrintSelection);
+ dlg.addEnabledOption(QAbstractPrintDialog::PrintPageRange);
+ dlg.addEnabledOption(QAbstractPrintDialog::PrintCollateCopies);
+
+ if (dlg.exec() == QDialog::Accepted)
viewer->print(printer);
- delete dlg;
}
#endif
}
connect(page, SIGNAL(sourceChanged(QUrl)), this, SLOT(handleSourceChanged(QUrl)));
connect(page, SIGNAL(forwardAvailable(bool)), this, SIGNAL(forwardAvailable(bool)));
connect(page, SIGNAL(backwardAvailable(bool)), this, SIGNAL(backwardAvailable(bool)));
+ connect(page, SIGNAL(printRequested()), this, SLOT(print()));
}
bool CentralWidget::eventFilter(QObject *object, QEvent *e)
using namespace Core::Constants;
using namespace Help::Internal;
-const char * const SB_INDEX = "Index";
-const char * const SB_CONTENTS = "Contents";
-const char * const SB_BOOKMARKS = "Bookmarks";
-const char * const SB_SEARCH = "Search";
+const char * const SB_INDEX = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Index");
+const char * const SB_CONTENTS = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Contents");
+const char * const SB_BOOKMARKS = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Bookmarks");
+const char * const SB_SEARCH = QT_TRANSLATE_NOOP("Help::Internal::HelpPlugin", "Search");
+
const char * const SB_OPENPAGES = "OpenPages";
#define IMAGEPATH ":/help/images/"
connect(action, SIGNAL(triggered()), this, SLOT(addBookmark()));
// Add Contents, Index, and Context menu items and a separator to the Help menu
- action = new QAction(QIcon::fromTheme(QLatin1String("help-contents")), tr("Contents"), this);
+ action = new QAction(QIcon::fromTheme(QLatin1String("help-contents")), tr(SB_CONTENTS), this);
cmd = am->registerAction(action, QLatin1String("Help.Contents"), globalcontext);
am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
connect(action, SIGNAL(triggered()), this, SLOT(activateContents()));
- action = new QAction(tr("Index"), this);
+ action = new QAction(tr(SB_INDEX), this);
cmd = am->registerAction(action, QLatin1String("Help.Index"), globalcontext);
am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP);
connect(action, SIGNAL(triggered()), this, SLOT(activateIndex()));
modecontext << m_core->uniqueIDManager()->uniqueIdentifier(Constants::C_MODE_HELP);
IndexWindow *indexWindow = new IndexWindow();
- indexWindow->setWindowTitle(tr("Index"));
+ indexWindow->setWindowTitle(tr(SB_INDEX));
m_indexItem = new Core::SideBarItem(indexWindow, QLatin1String(SB_INDEX));
connect(indexWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget,
shortcutMap.insert(QLatin1String(SB_INDEX), cmd);
ContentWindow *contentWindow = new ContentWindow();
- contentWindow->setWindowTitle(tr("Contents"));
+ contentWindow->setWindowTitle(tr(SB_CONTENTS));
m_contentItem = new Core::SideBarItem(contentWindow, QLatin1String(SB_CONTENTS));
connect(contentWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget,
SLOT(setSource(QUrl)));
shortcutMap.insert(QLatin1String(SB_CONTENTS), cmd);
SearchWidget *searchWidget = new SearchWidget();
- searchWidget->setWindowTitle(tr("Search"));
- m_searchItem = new Core::SideBarItem(searchWidget, "Search");
+ searchWidget->setWindowTitle(tr(SB_SEARCH));
+ m_searchItem = new Core::SideBarItem(searchWidget, QLatin1String(SB_SEARCH));
connect(searchWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget,
SLOT(setSourceFromSearch(QUrl)));
// modecontext);
// cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_S));
// connect(shortcut, SIGNAL(activated()), this, SLOT(activateSearch()));
- // shortcutMap.insert("Search", cmd);
+ // shortcutMap.insert(QLatin1String(SB_SEARCH), cmd);
BookmarkManager *manager = &LocalHelpManager::bookmarkManager();
BookmarkWidget *bookmarkWidget = new BookmarkWidget(manager, 0, false);
- bookmarkWidget->setWindowTitle(tr("Bookmarks"));
+ bookmarkWidget->setWindowTitle(tr(SB_BOOKMARKS));
m_bookmarkItem = new Core::SideBarItem(bookmarkWidget, QLatin1String(SB_BOOKMARKS));
connect(bookmarkWidget, SIGNAL(linkActivated(QUrl)), m_centralWidget,
SLOT(setSource(QUrl)));
// modecontext);
// cmd->setDefaultKeySequence(QKeySequence(Qt::CTRL + Qt::Key_B));
// connect(shortcut, SIGNAL(activated()), this, SLOT(activateBookmarks()));
- // shortcutMap.insert("Bookmarks", cmd);
+ // shortcutMap.insert(QLatin1String(SB_BOOKMARKS), cmd);
QWidget *openPagesWidget = OpenPagesManager::instance().openPagesWidget();
openPagesWidget->setWindowTitle(tr("Open Pages"));
void sourceChanged(const QUrl &);
void forwardAvailable(bool enabled);
void backwardAvailable(bool enabled);
+ void printRequested();
#else
void loadFinished(bool finished);
#endif
connect(this, SIGNAL(urlChanged(QUrl)), this, SIGNAL(sourceChanged(QUrl)));
connect(this, SIGNAL(loadFinished(bool)), this, SLOT(setLoadFinished(bool)));
connect(this, SIGNAL(titleChanged(QString)), this, SIGNAL(titleChanged()));
+ connect(page(), SIGNAL(printRequested(QWebFrame*)), this, SIGNAL(printRequested()));
setFont(viewerFont());
setTextSizeMultiplier(zoom == 0.0 ? 1.0 : zoom);
-<plugin name="Locator" version="2.0.80" compatVersion="2.0.80">
+<plugin name="Locator" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Provides the Locator widget and the hooks for Locator filter implementations.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
</dependencyList>
</plugin>
DirectoryFilter::DirectoryFilter()
: m_name(tr("Generic Directory Filter")),
m_filters(QStringList() << QLatin1String("*.h") << QLatin1String("*.cpp")
- << QLatin1String("*.ui") << QLatin1String("*.qrc"))
+ << QLatin1String("*.ui") << QLatin1String("*.qrc")),
+ m_dialog(0)
{
setIncludedByDefault(true);
}
QDir::Name|QDir::IgnoreCase|QDir::LocaleAware);
foreach (const QString &dir, dirs) {
if (dir != QLatin1String(".") && (name.isEmpty() || dir.startsWith(name, Qt::CaseInsensitive))) {
- FilterEntry entry(this, dir, dirInfo.filePath(dir));
- entry.resolveFileIcon = true;
- value.append(entry);
+ FilterEntry filterEntry(this, dir, dirInfo.filePath(dir));
+ filterEntry.resolveFileIcon = true;
+ value.append(filterEntry);
}
}
foreach (const QString &file, files) {
if (name.isEmpty() || file.startsWith(name, Qt::CaseInsensitive)) {
const QString fullPath = dirInfo.filePath(file);
- FilterEntry entry(this, file, fullPath);
- entry.resolveFileIcon = true;
- value.append(entry);
+ FilterEntry filterEntry(this, file, fullPath);
+ filterEntry.resolveFileIcon = true;
+ value.append(filterEntry);
}
}
return value;
if (entry.isEmpty()) {
foreach (ILocatorFilter *filter, m_plugin->filters()) {
if (!filter->shortcutString().isEmpty() && !filter->isHidden()) {
- FilterEntry entry(this,
+ FilterEntry filterEntry(this,
filter->shortcutString(),
QVariant::fromValue(filter),
m_icon);
- entry.extraInfo = filter->displayName();
- entries.append(entry);
+ filterEntry.extraInfo = filter->displayName();
+ entries.append(filterEntry);
}
}
}
const QRegExp regexp(pattern, Qt::CaseInsensitive, QRegExp::Wildcard);
if (!regexp.isValid())
return value;
- foreach (const OpenEditorsModel::Entry &entry, m_editors) {
- QString fileName = entry.fileName();
- QString displayName = entry.displayName();
+ foreach (const OpenEditorsModel::Entry &editorEntry, m_editors) {
+ QString fileName = editorEntry.fileName();
+ QString displayName = editorEntry.displayName();
if (regexp.exactMatch(displayName)) {
if (fileName.isEmpty()) {
- if (entry.editor)
- value.append(FilterEntry(this, displayName, qVariantFromValue(entry.editor)));
+ if (editorEntry.editor)
+ value.append(FilterEntry(this, displayName, qVariantFromValue(editorEntry.editor)));
} else {
QFileInfo fi(fileName);
- FilterEntry entry(this, fi.fileName(), fileName);
- entry.extraInfo = QDir::toNativeSeparators(fi.path());
- entry.resolveFileIcon = true;
- value.append(entry);
+ FilterEntry fiEntry(this, fi.fileName(), fileName);
+ fiEntry.extraInfo = QDir::toNativeSeparators(fi.path());
+ fiEntry.resolveFileIcon = true;
+ value.append(fiEntry);
}
}
}
-<plugin name="Mercurial" version="2.0.80" compatVersion="2.0.80">
+<plugin name="Mercurial" version="2.1.80" compatVersion="2.1.80">
<vendor>Brian McGillion</vendor>
<copyright>(C) 2008-2009 Brian McGillion</copyright>
<license>
<description>Mercurial integration.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
- <dependency name="Core" version="2.0.80"/>
- <dependency name="VCSBase" version="2.0.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
+ <dependency name="Core" version="2.1.80"/>
+ <dependency name="VCSBase" version="2.1.80"/>
</dependencyList>
</plugin>
QStringList args;
args << QLatin1String("add") << filename;
QByteArray stdOut;
- return executeHgSynchronously(workingDir, args, &stdOut);
+ return executeHgFullySynchronously(workingDir, args, &stdOut);
}
bool MercurialClient::remove(const QString &workingDir, const QString &filename)
QStringList args;
args << QLatin1String("remove") << filename;
QByteArray stdOut;
- return executeHgSynchronously(workingDir, args, &stdOut);
+ return executeHgFullySynchronously(workingDir, args, &stdOut);
+}
+
+bool MercurialClient::move(const QString &workingDir, const QString &from, const QString &to)
+{
+ QStringList args;
+ args << QLatin1String("rename") << from << to;
+ QByteArray stdOut;
+ return executeHgFullySynchronously(workingDir, args, &stdOut);
}
bool MercurialClient::manifestSync(const QString &repository, const QString &relativeFilename)
const QStringList args(QLatin1String("manifest"));
QByteArray output;
- executeHgSynchronously(repository, args, &output);
+ executeHgFullySynchronously(repository, args, &output);
const QDir repositoryDir(repository);
const QFileInfo needle = QFileInfo(repositoryDir, relativeFilename);
return false;
}
-bool MercurialClient::executeHgSynchronously(const QString &workingDir,
+Utils::SynchronousProcessResponse
+ MercurialClient::executeHgSynchronously(const QString &workingDirectory,
+ const QStringList &hgArgs,
+ unsigned flags,
+ QTextCodec *outputCodec)
+{
+ const MercurialSettings &settings = MercurialPlugin::instance()->settings();
+ const QString binary = settings.binary();
+ const QStringList arguments = settings.standardArguments() + hgArgs;
+ return VCSBase::VCSBasePlugin::runVCS(workingDirectory, binary, arguments,
+ settings.timeoutMilliSeconds(),
+ flags, outputCodec);
+}
+
+bool MercurialClient::executeHgFullySynchronously(const QString &workingDir,
const QStringList &args,
QByteArray *output) const
{
const QStringList arguments = settings.standardArguments() + args;
VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
- outputWindow->appendCommand(MercurialJobRunner::msgExecute(binary, arguments));
+ outputWindow->appendCommand(workingDir, binary, args);
hgProcess.start(binary, arguments);
QByteArray stdErr;
if (!Utils::SynchronousProcess::readDataFromProcess(hgProcess, settings.timeoutMilliSeconds(),
- output, &stdErr)) {
+ output, &stdErr, true)) {
Utils::SynchronousProcess::stopProcess(hgProcess);
outputWindow->appendError(MercurialJobRunner::msgTimeout(settings.timeoutSeconds()));
return false;
QString MercurialClient::branchQuerySync(const QString &repositoryRoot)
{
QByteArray output;
- if (executeHgSynchronously(repositoryRoot, QStringList(QLatin1String("branch")), &output))
+ if (executeHgFullySynchronously(repositoryRoot, QStringList(QLatin1String("branch")), &output))
return QTextCodec::codecForLocale()->toUnicode(output).trimmed();
return QLatin1String("Unknown Branch");
if (!file.isEmpty())
args << file;
QByteArray outputData;
- if (!executeHgSynchronously(workingDirectory, args, &outputData))
+ if (!executeHgFullySynchronously(workingDirectory, args, &outputData))
return false;
QString output = QString::fromLocal8Bit(outputData);
output.remove(QLatin1Char('\r'));
if (!format.isEmpty())
args << QLatin1String("--template") << format;
QByteArray outputData;
- if (!executeHgSynchronously(workingDirectory, args, &outputData))
+ if (!executeHgFullySynchronously(workingDirectory, args, &outputData))
return false;
*description = QString::fromLocal8Bit(outputData);
description->remove(QLatin1Char('\r'));
{
const QStringList args(QLatin1String("init"));
QByteArray outputData;
- if (!executeHgSynchronously(workingDirectory, args, &outputData))
+ if (!executeHgFullySynchronously(workingDirectory, args, &outputData))
return false;
QString output = QString::fromLocal8Bit(outputData);
output.remove(QLatin1Char('\r'));
enqueueJob(job);
}
-void MercurialClient::pull(const QString &repositoryRoot, const QString &repository)
+bool MercurialClient::pullSync(const QString &repositoryRoot, const QString &repository)
{
QStringList args(QLatin1String("pull"));
if (!repository.isEmpty())
args.append(repository);
- QSharedPointer<HgTask> job(new HgTask(repositoryRoot, args, false, QVariant(repositoryRoot)));
- connect(job.data(), SIGNAL(succeeded(QVariant)), this, SIGNAL(changed(QVariant)), Qt::QueuedConnection);
- enqueueJob(job);
+ // Disable UNIX terminals to suppress SSH prompting.
+ const unsigned flags = VCSBase::VCSBasePlugin::SshPasswordPrompt|VCSBase::VCSBasePlugin::ShowStdOutInLogWindow
+ |VCSBase::VCSBasePlugin::ShowSuccessMessage;
+ const Utils::SynchronousProcessResponse resp =
+ executeHgSynchronously(repositoryRoot, args, flags);
+ const bool ok = resp.result == Utils::SynchronousProcessResponse::Finished;
+ if (ok)
+ emit changed(QVariant(repositoryRoot));
+ return ok;
}
-void MercurialClient::push(const QString &repositoryRoot, const QString &repository)
+bool MercurialClient::pushSync(const QString &repositoryRoot, const QString &repository)
{
QStringList args(QLatin1String("push"));
if (!repository.isEmpty())
args.append(repository);
-
- QSharedPointer<HgTask> job(new HgTask(repositoryRoot, args, false));
- enqueueJob(job);
+ // Disable UNIX terminals to suppress SSH prompting.
+ const unsigned flags = VCSBase::VCSBasePlugin::SshPasswordPrompt|VCSBase::VCSBasePlugin::ShowStdOutInLogWindow
+ |VCSBase::VCSBasePlugin::ShowSuccessMessage;
+ const Utils::SynchronousProcessResponse resp =
+ executeHgSynchronously(repositoryRoot, args, flags);
+ return resp.result == Utils::SynchronousProcessResponse::Finished;
}
void MercurialClient::incoming(const QString &repositoryRoot, const QString &repository)
true, "incoming", id);
QSharedPointer<HgTask> job(new HgTask(repositoryRoot, args, editor));
+ // Suppress SSH prompting.
+ if (!repository.isEmpty() && VCSBase::VCSBasePlugin::isSshPromptConfigured())
+ job->setUnixTerminalDisabled(true);
enqueueJob(job);
}
"outgoing", repositoryRoot);
QSharedPointer<HgTask> job(new HgTask(repositoryRoot, args, editor));
+ // Suppress SSH prompting
+ job->setUnixTerminalDisabled(VCSBase::VCSBasePlugin::isSshPromptConfigured());
enqueueJob(job);
}
args << revision;
QSharedPointer<HgTask> job(new HgTask(repositoryRoot, args, false, QVariant(repositoryRoot)));
+ // Suppress SSH prompting
+ job->setUnixTerminalDisabled(VCSBase::VCSBasePlugin::isSshPromptConfigured());
connect(job.data(), SIGNAL(succeeded(QVariant)), this, SIGNAL(changed(QVariant)), Qt::QueuedConnection);
enqueueJob(job);
}
class VCSBaseEditor;
}
+namespace Utils {
+ struct SynchronousProcessResponse;
+}
+
namespace Mercurial {
namespace Internal {
~MercurialClient();
bool add(const QString &workingDir, const QString &fileName);
bool remove(const QString &workingDir, const QString &fileName);
+ bool move(const QString &workingDir, const QString &from, const QString &to);
bool manifestSync(const QString &repository, const QString &filename);
QString branchQuerySync(const QString &repositoryRoot);
bool parentRevisionsSync(const QString &workingDirectory,
void log(const QString &workingDir, const QStringList &files = QStringList(),
bool enableAnnotationContextMenu = false);
void import(const QString &repositoryRoot, const QStringList &files);
- void pull(const QString &repositoryRoot, const QString &repository = QString());
- void push(const QString &repositoryRoot, const QString &repository = QString());
+ bool pullSync(const QString &repositoryRoot, const QString &repository = QString());
+ bool pushSync(const QString &repositoryRoot, const QString &repository = QString());
void incoming(const QString &repositoryRoot, const QString &repository = QString());
void outgoing(const QString &repositoryRoot);
void status(const QString &workingDir, const QString &file = QString());
void slotAnnotateRevisionRequested(const QString &source, QString change, int lineNumber);
private:
- bool executeHgSynchronously(const QString &workingDir,
- const QStringList &args,
- QByteArray *output) const;
+ // Fully synchronous git execution (QProcess-based).
+ bool executeHgFullySynchronously(const QString &workingDir,
+ const QStringList &args,
+ QByteArray *output) const;
+ // Synchronous hg execution using Utils::SynchronousProcess, with
+ // log windows updating (using VCSBasePlugin::runVCS with flags).
+ inline Utils::SynchronousProcessResponse
+ executeHgSynchronously(const QString &workingDir, const QStringList &args,
+ unsigned flags = 0, QTextCodec *outputCodec = 0);
+
void enqueueJob(const QSharedPointer<HgTask> &);
void revert(const QString &workingDir, const QString &argument,
const QString &revision, const QVariant &cookie);
return tr("Mercurial");
}
-bool MercurialControl::managesDirectory(const QString &directory) const
+bool MercurialControl::managesDirectory(const QString &directory, QString *topLevel) const
{
QFileInfo dir(directory);
- return !mercurialClient->findTopLevelForFile(dir).isEmpty();
-}
-
-QString MercurialControl::findTopLevelForDirectory(const QString &directory) const
-{
- QFileInfo dir(directory);
- return mercurialClient->findTopLevelForFile(dir);
+ const QString topLevelFound = mercurialClient->findTopLevelForFile(dir);
+ if (topLevel)
+ *topLevel = topLevelFound;
+ return !topLevelFound.isEmpty();
}
bool MercurialControl::supportsOperation(Operation operation) const
switch (operation) {
case Core::IVersionControl::AddOperation:
case Core::IVersionControl::DeleteOperation:
+ case Core::IVersionControl::MoveOperation:
case Core::IVersionControl::CreateRepositoryOperation:
case Core::IVersionControl::AnnotateOperation:
break;
return mercurialClient->remove(fi.absolutePath(), fi.fileName());
}
+bool MercurialControl::vcsMove(const QString &from, const QString &to)
+{
+ const QFileInfo fromInfo(from);
+ const QFileInfo toInfo(to);
+ return mercurialClient->move(fromInfo.absolutePath(), fromInfo.absoluteFilePath(), toInfo.absoluteFilePath());
+}
+
bool MercurialControl::vcsCreateRepository(const QString &directory)
{
return mercurialClient->createRepositorySync(directory);
bool MercurialControl::sccManaged(const QString &filename)
{
const QFileInfo fi(filename);
- const QString topLevel = findTopLevelForDirectory(fi.absolutePath());
- if (topLevel.isEmpty())
+ QString topLevel;
+ const bool managed = managesDirectory(fi.absolutePath(), &topLevel);
+ if (!managed || topLevel.isEmpty())
return false;
const QDir topLevelDir(topLevel);
return mercurialClient->manifestSync(topLevel, topLevelDir.relativeFilePath(filename));
explicit MercurialControl(MercurialClient *mercurialClient);
QString displayName() const;
- bool managesDirectory(const QString &filename) const;
- QString findTopLevelForDirectory(const QString &directory) const;
+ bool managesDirectory(const QString &filename, QString *topLevel = 0) const;
bool supportsOperation(Operation operation) const;
bool vcsOpen(const QString &fileName);
bool vcsAdd(const QString &filename);
bool vcsDelete(const QString &filename);
+ bool vcsMove(const QString &from, const QString &to);
bool vcsCreateRepository(const QString &directory);
QString vcsCreateSnapshot(const QString &topLevel);
QStringList vcsSnapshots(const QString &topLevel);
#include <vcsbase/vcsbaseoutputwindow.h>
#include <vcsbase/vcsbaseeditor.h>
+#include <vcsbase/vcsbaseplugin.h>
#include <utils/synchronousprocess.h>
#include <QtCore/QProcess>
arguments(arguments),
emitRaw(emitRaw),
m_cookie(cookie),
- editor(0)
-
+ editor(0),
+ m_unixTerminalDisabled(false)
{
}
arguments(arguments),
emitRaw(false),
m_cookie(cookie),
- editor(editor)
+ editor(editor),
+ m_unixTerminalDisabled(false)
{
}
}
}
-QString MercurialJobRunner::msgExecute(const QString &binary, const QStringList &args)
-{
- return tr("Executing: %1 %2\n").arg(binary, args.join(QString(QLatin1Char(' '))));
-}
-
QString MercurialJobRunner::msgStartFailed(const QString &binary, const QString &why)
{
return tr("Unable to start mercurial process '%1': %2").arg(binary, why);
void MercurialJobRunner::setProcessEnvironment(QProcess &p)
{
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
- env.insert(QLatin1String("LANG"), QString(QLatin1Char('C')));
+ VCSBase::VCSBasePlugin::setProcessEnvironment(&env);
p.setProcessEnvironment(env);
}
}
const QStringList args = standardArguments + taskData->args();
- emit commandStarted(msgExecute(binary, args));
+ emit commandStarted(VCSBase::VCSBaseOutputWindow::msgExecutionLogEntry(taskData->repositoryRoot(), binary, args));
//infom the user of what we are going to try and perform
if (Constants::debug)
- qDebug() << Q_FUNC_INFO << "Repository root is " << taskData->repositoryRoot();
+ qDebug() << Q_FUNC_INFO << "Repository root is "
+ << taskData->repositoryRoot() << " terminal_disabled"
+ << taskData->unixTerminalDisabled();
+
+ const unsigned processFlags = taskData->unixTerminalDisabled() ?
+ unsigned(Utils::SynchronousProcess::UnixTerminalDisabled) :
+ unsigned(0);
- QProcess hgProcess;
- hgProcess.setWorkingDirectory(taskData->repositoryRoot());
- MercurialJobRunner::setProcessEnvironment(hgProcess);
+ QSharedPointer<QProcess> hgProcess = Utils::SynchronousProcess::createProcess(processFlags);
+ hgProcess->setWorkingDirectory(taskData->repositoryRoot());
+ MercurialJobRunner::setProcessEnvironment(*hgProcess);
- hgProcess.start(binary, args);
+ hgProcess->start(binary, args);
- if (!hgProcess.waitForStarted()) {
- emit error(msgStartFailed(binary, hgProcess.errorString()));
+ if (!hgProcess->waitForStarted()) {
+ emit error(msgStartFailed(binary, hgProcess->errorString()));
return;
}
- hgProcess.closeWriteChannel();
+ hgProcess->closeWriteChannel();
QByteArray stdOutput;
QByteArray stdErr;
- if (!Utils::SynchronousProcess::readDataFromProcess(hgProcess, m_timeoutMS, &stdOutput, &stdErr)) {
- Utils::SynchronousProcess::stopProcess(hgProcess);
+ if (!Utils::SynchronousProcess::readDataFromProcess(*hgProcess, m_timeoutMS, &stdOutput, &stdErr, false)) {
+ Utils::SynchronousProcess::stopProcess(*hgProcess);
emit error(msgTimeout(m_timeoutMS / 1000));
return;
}
- if (hgProcess.exitStatus() == QProcess::NormalExit && hgProcess.exitCode() == 0) {
+ if (hgProcess->exitStatus() == QProcess::NormalExit && hgProcess->exitCode() == 0) {
/*
* sometimes success means output is actually on error channel (stderr)
* e.g. "hg revert" outputs "no changes needed to 'file'" on stderr if file has not changed
emit error(QString::fromLocal8Bit(stdErr));
}
- hgProcess.close();
+ hgProcess->close();
//the signal connection is to last only for the duration of a job/task. next time a new
//output signal connection must be made
disconnect(this, SIGNAL(output(QByteArray)), 0, 0);
QStringList args() { return arguments; }
QString repositoryRoot() { return m_repositoryRoot; }
+ // Disable terminal to suppress SSH prompting.
+ bool unixTerminalDisabled() const { return m_unixTerminalDisabled; }
+ void setUnixTerminalDisabled(bool v) { m_unixTerminalDisabled = v; }
+
signals:
void succeeded(const QVariant &cookie); // Use a queued connection
void rawData(const QByteArray &data);
const bool emitRaw;
const QVariant m_cookie;
VCSBase::VCSBaseEditor *editor;
+ bool m_unixTerminalDisabled;
};
/* A job queue running in a separate thread, executing commands
void enqueueJob(const QSharedPointer<HgTask> &job);
void restart();
- static QString msgExecute(const QString &binary, const QStringList &args);
static QString msgStartFailed(const QString &binary, const QString &why);
static QString msgTimeout(int timeoutSeconds);
dialog.setWindowTitle(tr("Pull Source"));
if (dialog.exec() != QDialog::Accepted)
return;
- m_client->pull(state.topLevel(), dialog.getRepositoryString());
+ m_client->pullSync(state.topLevel(), dialog.getRepositoryString());
}
void MercurialPlugin::push()
dialog.setWindowTitle(tr("Push Destination"));
if (dialog.exec() != QDialog::Accepted)
return;
- m_client->push(state.topLevel(), dialog.getRepositoryString());
+ m_client->pushSync(state.topLevel(), dialog.getRepositoryString());
}
void MercurialPlugin::update()
-<plugin name="Perforce" version="2.0.80" compatVersion="2.0.80">
+<plugin name="Perforce" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Perforce integration.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
- <dependency name="Core" version="2.0.80"/>
- <dependency name="VCSBase" version="2.0.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
+ <dependency name="Core" version="2.1.80"/>
+ <dependency name="VCSBase" version="2.1.80"/>
</dependencyList>
</plugin>
m_updateAllAction->setEnabled(true);
}
-bool PerforcePlugin::managesDirectory(const QString &directory)
+bool PerforcePlugin::managesDirectory(const QString &directory, QString *topLevel /* = 0 */)
+{
+ const bool rc = managesDirectoryFstat(directory);
+ if (topLevel) {
+ if (rc) {
+ *topLevel = m_settings.topLevelSymLinkTarget();
+ } else {
+ topLevel->clear();
+ }
+ }
+ return rc;
+}
+
+bool PerforcePlugin::managesDirectoryFstat(const QString &directory)
{
if (!m_settings.isValid())
return false;
return managed;
}
-QString PerforcePlugin::findTopLevelForDirectory(const QString &dir)
-{
- if (!m_settings.isValid())
- return QString();
- return managesDirectory(dir) ? m_settings.topLevelSymLinkTarget() : QString();
-}
-
bool PerforcePlugin::vcsOpen(const QString &workingDir, const QString &fileName)
{
if (Perforce::Constants::debug)
return !deleteResult.error;
}
-static QString formatCommand(const QString &cmd, const QStringList &args)
+bool PerforcePlugin::vcsMove(const QString &workingDir, const QString &from, const QString &to)
{
- const QChar blank = QLatin1Char(' ');
- QString command = cmd;
- command += blank;
- command += args.join(QString(blank));
- return PerforcePlugin::tr("Executing: %1\n").arg(command);
+ // TODO verify this works
+ QStringList args;
+ args << QLatin1String("edit") << from;
+ const PerforceResponse editResult = runP4Cmd(workingDir, args,
+ CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
+ if (editResult.error)
+ return false;
+ args.clear();
+ args << QLatin1String("move") << from << to;
+ const PerforceResponse moveResult = runP4Cmd(workingDir, args,
+ CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
+ return !moveResult.error;
}
// Write extra args to temporary file
}
if (Perforce::Constants::debug)
qDebug() << "PerforcePlugin::run syncp actual args [" << process.workingDirectory() << ']' << args;
+ process.setTimeOutMessageBoxEnabled(true);
const Utils::SynchronousProcessResponse sp_resp = process.run(m_settings.p4Command(), args);
if (Perforce::Constants::debug)
qDebug() << sp_resp;
QByteArray stdOut;
QByteArray stdErr;
const int timeOut = (flags & LongTimeOut) ? m_settings.longTimeOutMS() : m_settings.timeOutMS();
- if (!Utils::SynchronousProcess::readDataFromProcess(process, timeOut, &stdOut, &stdErr)) {
+ if (!Utils::SynchronousProcess::readDataFromProcess(process, timeOut, &stdOut, &stdErr, true)) {
Utils::SynchronousProcess::stopProcess(process);
response.error = true;
response.message = msgTimeout(timeOut);
actualArgs.append(args);
if (flags & CommandToWindow)
- outputWindow->appendCommand(formatCommand(m_settings.p4Command(), actualArgs));
+ outputWindow->appendCommand(workingDir, m_settings.p4Command(), actualArgs);
if (flags & ShowBusyCursor)
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
bool initialize(const QStringList &arguments, QString *error_message);
void extensionsInitialized();
- bool managesDirectory(const QString &directory);
- QString findTopLevelForDirectory(const QString &directory);
+ bool managesDirectory(const QString &directory, QString *topLevel = 0);
bool vcsOpen(const QString &workingDir, const QString &fileName);
bool vcsAdd(const QString &workingDir, const QString &fileName);
bool vcsDelete(const QString &workingDir, const QString &filename);
+ bool vcsMove(const QString &workingDir, const QString &from, const QString &to);
void p4Diff(const QString &workingDir, const QStringList &files);
void updateCheckout(const QString &workingDir = QString(),
const QStringList &dirs = QStringList());
bool revertProject(const QString &workingDir, const QStringList &args, bool unchangedOnly);
+ bool managesDirectoryFstat(const QString &directory);
inline PerforceVersionControl *perforceVersionControl() const;
switch (operation) {
case AddOperation:
case DeleteOperation:
+ case MoveOperation:
case OpenOperation:
case AnnotateOperation:
return true;
return m_plugin->vcsDelete(fi.absolutePath(), fi.fileName());
}
+bool PerforceVersionControl::vcsMove(const QString &from, const QString &to)
+{
+ const QFileInfo fromInfo(from);
+ const QFileInfo toInfo(to);
+ return m_plugin->vcsMove(fromInfo.absolutePath(), fromInfo.absoluteFilePath(), toInfo.absoluteFilePath());
+}
+
bool PerforceVersionControl::vcsCreateRepository(const QString &)
{
return false;
return true;
}
-bool PerforceVersionControl::managesDirectory(const QString &directory) const
-{
- const bool rc = m_plugin->managesDirectory(directory);
- if (Perforce::Constants::debug)
- qDebug() << "managesDirectory" << directory << rc;
- return rc;
-}
-
-QString PerforceVersionControl::findTopLevelForDirectory(const QString &directory) const
+bool PerforceVersionControl::managesDirectory(const QString &directory, QString *topLevel) const
{
- const QString rc = m_plugin->findTopLevelForDirectory(directory);
- if (Perforce::Constants::debug)
- qDebug() << "findTopLevelForDirectory" << directory << rc;
+ const bool rc = m_plugin->managesDirectory(directory, topLevel);
+ if (Perforce::Constants::debug) {
+ QDebug nsp = qDebug().nospace();
+ nsp << "managesDirectory" << directory << rc;
+ if (topLevel)
+ nsp << topLevel;
+ }
return rc;
}
virtual QString displayName() const;
- bool managesDirectory(const QString &directory) const;
- virtual QString findTopLevelForDirectory(const QString &directory) const;
+ virtual bool managesDirectory(const QString &directory, QString *topLevel = 0) const;
+
virtual bool supportsOperation(Operation operation) const;
virtual bool vcsOpen(const QString &fileName);
virtual bool vcsAdd(const QString &fileName);
virtual bool vcsDelete(const QString &filename);
+ virtual bool vcsMove(const QString &from, const QString &to);
virtual bool vcsCreateRepository(const QString &directory);
virtual QString vcsCreateSnapshot(const QString &topLevel);
virtual QStringList vcsSnapshots(const QString &topLevel);
SUBDIRS += plugin_qmlprojectmanager
- include(private_headers.pri)
+ include(../private_headers.pri)
exists($${QT_PRIVATE_HEADERS}/QtDeclarative/private/qdeclarativecontext_p.h) {
SUBDIRS += plugin_qmldesigner \
plugin_qmlinspector
+++ /dev/null
-# Try to find location of Qt private headers (see README)
-isEmpty(QT_PRIVATE_HEADERS) {
- QT_PRIVATE_HEADERS = $$[QT_INSTALL_HEADERS]
-} else {
- INCLUDEPATH += $$quote($${QT_PRIVATE_HEADERS}) \
- $$quote($${QT_PRIVATE_HEADERS}/QtDeclarative) \
- $$quote($${QT_PRIVATE_HEADERS}/QtCore) \
- $$quote($${QT_PRIVATE_HEADERS}/QtScript) \
- $$quote($${QT_PRIVATE_HEADERS}/QtGui)
-}
-<plugin name="ProjectExplorer" version="2.0.80" compatVersion="2.0.80">
+<plugin name="ProjectExplorer" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>ProjectExplorer framework that can be extended with different kind of project types.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
- <dependency name="Find" version="2.0.80"/>
- <dependency name="Locator" version="2.0.80"/>
- <dependency name="TextEditor" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
+ <dependency name="Find" version="2.1.80"/>
+ <dependency name="Locator" version="2.1.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
</dependencyList>
<argumentList>
<argument name="-customwizard-verbose">Verbose loading of custom wizards</argument>
void ApplicationLauncher::stop()
{
+ if (!isRunning())
+ return;
if (m_currentMode == Gui) {
m_winGuiProcess->stop();
} else {
m_consoleProcess->stop();
+ processStopped();
}
}
void ApplicationLauncher::stop()
{
+ if (!isRunning())
+ return;
if (m_currentMode == Gui) {
m_guiProcess->terminate();
if (!m_guiProcess->waitForFinished(1000)) { // This is blocking, so be fast.
}
} else {
m_consoleProcess->stop();
+ processStopped();
}
}
RunControl *LocalApplicationRunControlFactory::create(ProjectExplorer::RunConfiguration *runConfiguration, const QString &mode)
{
QTC_ASSERT(canRun(runConfiguration, mode), return 0);
- return new LocalApplicationRunControl(qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration));
+ return new LocalApplicationRunControl(qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration), mode);
}
QWidget *LocalApplicationRunControlFactory::createConfigurationWidget(RunConfiguration *runConfiguration)
// ApplicationRunControl
-LocalApplicationRunControl::LocalApplicationRunControl(LocalApplicationRunConfiguration *runConfiguration)
- : RunControl(runConfiguration)
+LocalApplicationRunControl::LocalApplicationRunControl(LocalApplicationRunConfiguration *runConfiguration, QString mode)
+ : RunControl(runConfiguration, mode)
{
m_applicationLauncher.setEnvironment(runConfiguration->environment().toStringList());
m_applicationLauncher.setWorkingDirectory(runConfiguration->workingDirectory());
{
Q_OBJECT
public:
- LocalApplicationRunControl(LocalApplicationRunConfiguration *runConfiguration);
+ LocalApplicationRunControl(LocalApplicationRunConfiguration *runConfiguration, QString mode);
virtual ~LocalApplicationRunControl();
virtual void start();
virtual void stop();
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "buildconfigurationmodel.h"
+#include "target.h"
+#include "buildconfiguration.h"
+
+using namespace ProjectExplorer;
+
+///
+/// RunConfigurationsModel
+///
+
+class BuildConfigurationComparer
+{
+public:
+ bool operator()(BuildConfiguration *a, BuildConfiguration *b)
+ {
+ return a->displayName() < b->displayName();
+ }
+};
+
+BuildConfigurationModel::BuildConfigurationModel(Target *target, QObject *parent)
+ : QAbstractListModel(parent),
+ m_target(target)
+{
+ m_buildConfigurations = m_target->buildConfigurations();
+ qSort(m_buildConfigurations.begin(), m_buildConfigurations.end(), BuildConfigurationComparer());
+
+ connect(target, SIGNAL(addedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
+ this, SLOT(addedBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
+ connect(target, SIGNAL(removedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
+ this, SLOT(removedBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
+
+ foreach (BuildConfiguration *bc, m_buildConfigurations)
+ connect(bc, SIGNAL(displayNameChanged()),
+ this, SLOT(displayNameChanged()));
+}
+
+int BuildConfigurationModel::rowCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? 0 : m_buildConfigurations.size();
+}
+
+int BuildConfigurationModel::columnCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? 0 : 1;
+}
+
+void BuildConfigurationModel::displayNameChanged()
+{
+ BuildConfiguration *rc = qobject_cast<BuildConfiguration *>(sender());
+ if (!rc)
+ return;
+
+ BuildConfigurationComparer compare;
+ // Find the old position
+ int oldPos = m_buildConfigurations.indexOf(rc);
+
+ if (oldPos >= 1 && compare(m_buildConfigurations.at(oldPos), m_buildConfigurations.at(oldPos - 1))) {
+ // We need to move up
+ int newPos = oldPos - 1;
+ while (newPos >= 0 && compare(m_buildConfigurations.at(oldPos), m_buildConfigurations.at(newPos))) {
+ --newPos;
+ }
+ ++newPos;
+
+ beginMoveRows(QModelIndex(), oldPos, oldPos, QModelIndex(), newPos);
+ m_buildConfigurations.insert(newPos, rc);
+ m_buildConfigurations.removeAt(oldPos + 1);
+ endMoveRows();
+ // Not only did we move, we also changed...
+ emit dataChanged(index(newPos, 0), index(newPos,0));
+ } else if (oldPos < m_buildConfigurations.size() - 1
+ && compare(m_buildConfigurations.at(oldPos + 1), m_buildConfigurations.at(oldPos))) {
+ // We need to move down
+ int newPos = oldPos + 1;
+ while (newPos < m_buildConfigurations.size()
+ && compare(m_buildConfigurations.at(newPos), m_buildConfigurations.at(oldPos))) {
+ ++newPos;
+ }
+ beginMoveRows(QModelIndex(), oldPos, oldPos, QModelIndex(), newPos);
+ m_buildConfigurations.insert(newPos, rc);
+ m_buildConfigurations.removeAt(oldPos);
+ endMoveRows();
+
+ // We need to subtract one since removing at the old place moves the newIndex down
+ emit dataChanged(index(newPos - 1, 0), index(newPos - 1, 0));
+ } else {
+ emit dataChanged(index(oldPos, 0), index(oldPos, 0));
+ }
+}
+
+QVariant BuildConfigurationModel::data(const QModelIndex &index, int role) const
+{
+ if (role == Qt::DisplayRole) {
+ const int row = index.row();
+ if (row < m_buildConfigurations.size()) {
+ return m_buildConfigurations.at(row)->displayName();
+ }
+ }
+
+ return QVariant();
+}
+
+BuildConfiguration *BuildConfigurationModel::buildConfigurationAt(int i)
+{
+ if (i > m_buildConfigurations.size() || i < 0)
+ return 0;
+ return m_buildConfigurations.at(i);
+}
+
+BuildConfiguration *BuildConfigurationModel::buildConfigurationFor(const QModelIndex &idx)
+{
+ if (idx.row() > m_buildConfigurations.size() || idx.row() < 0)
+ return 0;
+ return m_buildConfigurations.at(idx.row());
+}
+
+QModelIndex BuildConfigurationModel::indexFor(BuildConfiguration *rc)
+{
+ int idx = m_buildConfigurations.indexOf(rc);
+ if (idx == -1)
+ return QModelIndex();
+ return index(idx, 0);
+}
+
+void BuildConfigurationModel::addedBuildConfiguration(ProjectExplorer::BuildConfiguration *bc)
+{
+ // Find the right place to insert
+ BuildConfigurationComparer compare;
+ int i = 0;
+ for (; i < m_buildConfigurations.size(); ++i) {
+ if (compare(bc, m_buildConfigurations.at(i))) {
+ break;
+ }
+ }
+
+ beginInsertRows(QModelIndex(), i, i);
+ m_buildConfigurations.insert(i, bc);
+ endInsertRows();
+
+
+ connect(bc, SIGNAL(displayNameChanged()),
+ this, SLOT(displayNameChanged()));
+}
+
+void BuildConfigurationModel::removedBuildConfiguration(ProjectExplorer::BuildConfiguration *bc)
+{
+ int i = m_buildConfigurations.indexOf(bc);
+ beginRemoveRows(QModelIndex(), i, i);
+ m_buildConfigurations.removeAt(i);
+ endRemoveRows();
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef BUILDCONFIGURATIONMODEL_H
+#define BUILDCONFIGURATIONMODEL_H
+
+#include <QtCore/QAbstractItemModel>
+
+namespace ProjectExplorer {
+class Target;
+class BuildConfiguration;
+
+/*! A model to represent the build configurations of a target.
+ To be used in for the drop down of comboboxes
+ Does automatically adjust itself to added and removed BuildConfigurations
+ Very similar to the Run Configuration Model
+ TOOD might it possible to share code without making the code a complete mess
+*/
+class BuildConfigurationModel : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+ BuildConfigurationModel(Target *target, QObject *parent = 0);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+ BuildConfiguration *buildConfigurationAt(int i);
+ BuildConfiguration *buildConfigurationFor(const QModelIndex &idx);
+ QModelIndex indexFor(BuildConfiguration *rc);
+private slots:
+ void addedBuildConfiguration(ProjectExplorer::BuildConfiguration*);
+ void removedBuildConfiguration(ProjectExplorer::BuildConfiguration*);
+ void displayNameChanged();
+private:
+ Target *m_target;
+ QList<BuildConfiguration *> m_buildConfigurations;
+};
+
+}
+
+#endif // RUNCONFIGURATIONMODEL_H
#include "project.h"
#include "target.h"
#include "buildconfiguration.h"
+#include "buildconfigurationmodel.h"
#include <coreplugin/coreconstants.h>
#include <extensionsystem/pluginmanager.h>
BuildSettingsWidget::BuildSettingsWidget(Target *target) :
m_target(target),
- m_buildConfiguration(0),
- m_leftMargin(0)
+ m_buildConfiguration(0)
{
Q_ASSERT(m_target);
setupUi();
void BuildSettingsWidget::setupUi()
{
- m_leftMargin = Constants::PANEL_LEFT_MARGIN;
QVBoxLayout *vbox = new QVBoxLayout(this);
vbox->setContentsMargins(0, 0, 0, 0);
{ // Edit Build Configuration row
QHBoxLayout *hbox = new QHBoxLayout();
- hbox->setContentsMargins(m_leftMargin, 0, 0, 0);
+ hbox->setContentsMargins(0, 0, 0, 0);
hbox->addWidget(new QLabel(tr("Edit build configuration:"), this));
m_buildConfigurationComboBox = new QComboBox(this);
m_buildConfigurationComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
+ m_buildConfigurationComboBox->setModel(new BuildConfigurationModel(m_target, this));
hbox->addWidget(m_buildConfigurationComboBox);
m_addButton = new QPushButton(this);
}
m_buildConfiguration = m_target->activeBuildConfiguration();
+ BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildConfigurationComboBox->model());
+ m_buildConfigurationComboBox->setCurrentIndex(model->indexFor(m_buildConfiguration).row());
updateAddButtonMenu();
updateBuildSettings();
connect(m_target, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
this, SLOT(updateActiveConfiguration()));
- connect(m_target, SIGNAL(addedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
- this, SLOT(addedBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
-
- connect(m_target, SIGNAL(removedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
- this, SLOT(removedBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
-
- foreach (BuildConfiguration *bc, m_target->buildConfigurations()) {
- connect(bc, SIGNAL(displayNameChanged()),
- this, SLOT(buildConfigurationDisplayNameChanged()));
- }
-
if (m_target->buildConfigurationFactory())
connect(m_target->buildConfigurationFactory(), SIGNAL(availableCreationIdsChanged()),
SLOT(updateAddButtonMenu()));
}
-void BuildSettingsWidget::addedBuildConfiguration(BuildConfiguration *bc)
-{
- connect(bc, SIGNAL(displayNameChanged()),
- this, SLOT(buildConfigurationDisplayNameChanged()));
-}
-
-void BuildSettingsWidget::removedBuildConfiguration(BuildConfiguration *bc)
-{
- disconnect(bc, SIGNAL(displayNameChanged()),
- this, SLOT(buildConfigurationDisplayNameChanged()));
-}
-
-void BuildSettingsWidget::buildConfigurationDisplayNameChanged()
-{
- for (int i = 0; i < m_buildConfigurationComboBox->count(); ++i) {
- BuildConfiguration *bc = m_buildConfigurationComboBox->itemData(i).value<BuildConfiguration *>();
- m_buildConfigurationComboBox->setItemText(i, bc->displayName());
- }
-}
-
void BuildSettingsWidget::addSubWidget(const QString &name, BuildConfigWidget *widget)
{
- widget->setContentsMargins(m_leftMargin, 10, 0, 0);
+ widget->setContentsMargins(0, 10, 0, 0);
QLabel *label = new QLabel(this);
label->setText(name);
f.setPointSizeF(f.pointSizeF() * 1.2);
label->setFont(f);
- label->setContentsMargins(m_leftMargin, 10, 0, 0);
+ label->setContentsMargins(0, 10, 0, 0);
layout()->addWidget(label);
layout()->addWidget(widget);
void BuildSettingsWidget::updateAddButtonMenu()
{
m_addButtonMenu->clear();
- if (m_target &&
- m_target->activeBuildConfiguration()) {
- m_addButtonMenu->addAction(tr("&Clone Selected"),
- this, SLOT(cloneConfiguration()));
- }
- IBuildConfigurationFactory *factory = m_target->buildConfigurationFactory();
- if (factory) {
- foreach (const QString &id, factory->availableCreationIds(m_target)) {
- QAction *action = m_addButtonMenu->addAction(factory->displayNameForId(id), this, SLOT(createConfiguration()));
- action->setData(id);
+ if (m_target) {
+ if (m_target->activeBuildConfiguration()) {
+ m_addButtonMenu->addAction(tr("&Clone Selected"),
+ this, SLOT(cloneConfiguration()));
+ }
+ IBuildConfigurationFactory *factory = m_target->buildConfigurationFactory();
+ if (factory) {
+ foreach (const QString &id, factory->availableCreationIds(m_target)) {
+ QAction *action = m_addButtonMenu->addAction(factory->displayNameForId(id), this, SLOT(createConfiguration()));
+ action->setData(id);
+ }
}
}
}
void BuildSettingsWidget::updateBuildSettings()
{
- // Delete old tree items
- bool blocked = m_buildConfigurationComboBox->blockSignals(true);
- m_buildConfigurationComboBox->clear();
clear();
// update buttons
foreach (BuildConfigWidget *subConfigWidget, subConfigWidgets)
addSubWidget(subConfigWidget->displayName(), subConfigWidget);
- // Add tree items
- foreach (BuildConfiguration *bc, m_target->buildConfigurations()) {
- m_buildConfigurationComboBox->addItem(bc->displayName(), QVariant::fromValue<BuildConfiguration *>(bc));
- if (bc == m_buildConfiguration)
- m_buildConfigurationComboBox->setCurrentIndex(m_buildConfigurationComboBox->count() - 1);
- }
-
foreach (BuildConfigWidget *widget, subWidgets())
widget->init(m_buildConfiguration);
-
- m_buildConfigurationComboBox->blockSignals(blocked);
}
void BuildSettingsWidget::currentIndexChanged(int index)
{
- BuildConfiguration *buildConfiguration = m_buildConfigurationComboBox->itemData(index).value<BuildConfiguration *>();
+ BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildConfigurationComboBox->model());
+ BuildConfiguration *buildConfiguration = model->buildConfigurationAt(index);
m_target->setActiveBuildConfiguration(buildConfiguration);
}
m_buildConfiguration = m_target->activeBuildConfiguration();
- for (int i = 0; i < m_buildConfigurationComboBox->count(); ++i) {
- if (m_buildConfigurationComboBox->itemData(i).value<BuildConfiguration *>() == m_buildConfiguration) {
- m_buildConfigurationComboBox->setCurrentIndex(i);
- break;
- }
- }
+ BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildConfigurationComboBox->model());
+ m_buildConfigurationComboBox->setCurrentIndex(model->indexFor(m_buildConfiguration).row());
foreach (QWidget *widget, subWidgets()) {
if (BuildConfigWidget *buildStepWidget = qobject_cast<BuildConfigWidget*>(widget)) {
QString displayName() const;
QWidget *widget() const;
QIcon icon() const;
- PanelFlags flags() const { return IPropertiesPanel::NoLeftMargin; }
private:
BuildSettingsWidget *m_widget;
void deleteConfiguration();
void updateAddButtonMenu();
- void addedBuildConfiguration(ProjectExplorer::BuildConfiguration *bc);
- void removedBuildConfiguration(ProjectExplorer::BuildConfiguration *bc);
- void buildConfigurationDisplayNameChanged();
void updateActiveConfiguration();
private:
QList<BuildConfigWidget *> m_subWidgets;
QList<QLabel *> m_labels;
-
- int m_leftMargin;
};
} // namespace Internal
BuildStepsPage::BuildStepsPage(Target *target, StepType type) :
BuildConfigWidget(),
m_type(type),
- m_addButton(0),
- m_leftMargin(-1)
+ m_addButton(0)
{
Q_UNUSED(target);
+ setStyleSheet("background: red");
}
BuildStepsPage::~BuildStepsPage()
s.detailsWidget->setToolWidget(toolWidget);
- const int leftMargin(qMax(m_leftMargin - toolWidget->width(), 0));
- s.detailsWidget->setContentsMargins(leftMargin, 0, 0, 1);
+ s.detailsWidget->setContentsMargins(0, 0, 0, 1);
m_buildSteps.insert(pos, s);
if (0 != m_addButton)
return;
- QMargins margins(contentsMargins());
- m_leftMargin = margins.left();
- margins.setLeft(0);
- setContentsMargins(margins);
-
m_upMapper = new QSignalMapper(this);
connect(m_upMapper, SIGNAL(mapped(int)),
this, SLOT(stepMoveUp(int)));
m_vbox->setSpacing(0);
m_noStepsLabel = new QLabel(tr("No Build Steps"), this);
- m_noStepsLabel->setContentsMargins(m_leftMargin, 0, 0, 0);
+ m_noStepsLabel->setContentsMargins(0, 0, 0, 0);
m_vbox->addWidget(m_noStepsLabel);
QHBoxLayout *hboxLayout = new QHBoxLayout();
- hboxLayout->setContentsMargins(m_leftMargin, 4, 0, 0);
+ hboxLayout->setContentsMargins(0, 4, 0, 0);
m_addButton = new QPushButton(this);
m_addButton->setText(m_type == Clean ? tr("Add Clean Step") : tr("Add Build Step"));
m_addButton->setMenu(new QMenu(this));
#include <QtGui/QLabel>
#include <QtGui/QRegExpValidator>
#include <QtGui/QComboBox>
+#include <QtGui/QTextEdit>
enum { debug = 0 };
{
}
+CustomWizardFieldPage::TextEditData::TextEditData(QTextEdit* le, const QString &defText) :
+ textEdit(le), defaultText(defText)
+{
+}
+
CustomWizardFieldPage::CustomWizardFieldPage(const QSharedPointer<CustomWizardContext> &ctx,
const FieldList &fields,
QWidget *parent) :
m_context(ctx),
m_formLayout(new QFormLayout)
{
+ m_formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
if (debug)
qDebug() << Q_FUNC_INFO << fields.size();
foreach(const CustomWizardField &f, fields)
QWidget *fieldWidget = 0;
if (className == QLatin1String("QComboBox")) {
fieldWidget = registerComboBox(fieldName, field);
+ } else if (className == QLatin1String("QTextEdit")) {
+ fieldWidget = registerTextEdit(fieldName, field);
+ } else if (className == QLatin1String("Utils::PathChooser")) {
+ fieldWidget = registerPathChooser(fieldName, field);
} else {
fieldWidget = registerLineEdit(fieldName, field);
}
return combo;
} // QComboBox
+QWidget *CustomWizardFieldPage::registerTextEdit(const QString &fieldName,
+ const CustomWizardField &field)
+{
+ QTextEdit *textEdit = new QTextEdit;
+ registerField(fieldName, textEdit, "plainText", SIGNAL(textChanged(QString)));
+ const QString defaultText = field.controlAttributes.value(QLatin1String("defaulttext"));
+ m_textEdits.push_back(TextEditData(textEdit, defaultText));
+ return textEdit;
+} // QTextEdit
+
+QWidget *CustomWizardFieldPage::registerPathChooser(const QString &fieldName,
+ const CustomWizardField &field)
+{
+ Utils::PathChooser *pathChooser = new Utils::PathChooser;
+ registerField(fieldName, pathChooser, "path", SIGNAL(changed(QString)));
+ return pathChooser;
+} // Utils::PathChooser
+
QWidget *CustomWizardFieldPage::registerLineEdit(const QString &fieldName,
const CustomWizardField &field)
{
led.lineEdit->setText(defaultText);
}
}
+ foreach(const TextEditData &ted, m_textEdits) {
+ if (!ted.defaultText.isEmpty()) {
+ QString defaultText = ted.defaultText;
+ CustomWizardContext::replaceFields(m_context->baseReplacements, &defaultText);
+ ted.textEdit->setText(defaultText);
+ }
+ }
}
bool CustomWizardFieldPage::validatePage()
QT_BEGIN_NAMESPACE
class QFormLayout;
class QLineEdit;
+class QTextEdit;
QT_END_NAMESPACE
namespace Utils {
QLineEdit* lineEdit;
QString defaultText;
};
+ struct TextEditData {
+ explicit TextEditData(QTextEdit* le = 0, const QString &defText = QString());
+ QTextEdit* textEdit;
+ QString defaultText;
+ };
typedef QList<LineEditData> LineEditDataList;
+ typedef QList<TextEditData> TextEditDataList;
QWidget *registerLineEdit(const QString &fieldName, const CustomWizardField &field);
QWidget *registerComboBox(const QString &fieldName, const CustomWizardField &field);
-
+ QWidget *registerTextEdit(const QString &fieldName, const CustomWizardField &field);
+ QWidget *registerPathChooser(const QString &fieldName, const CustomWizardField &field);
void addField(const CustomWizardField &f);
const QSharedPointer<CustomWizardContext> m_context;
QFormLayout *m_formLayout;
LineEditDataList m_lineEdits;
+ TextEditDataList m_textEdits;
};
// A custom wizard page presenting the fields to be used and a path chooser
#endif
const QChar slash = QLatin1Char('/');
foreach (const QString &p, path()) {
-// qDebug()<<"trying"<<path + '/' + executable;
+// qDebug()<<"trying"<<p + '/' + executable;
QString fp = p;
fp += slash;
fp += executable;
#else
const QChar sep = QLatin1Char(':');
#endif
- return m_values.value(QLatin1String("PATH")).split(sep);
+ return m_values.value(QLatin1String("PATH")).split(sep, QString::SkipEmptyParts);
}
QString Environment::value(const QString &key) const
class PROJECTEXPLORER_EXPORT IPropertiesPanel
{
public:
- enum PanelFlag {
- NoFlag = 0x00,
- NoLeftMargin = 0x01
- };
- Q_DECLARE_FLAGS(PanelFlags, PanelFlag)
-
IPropertiesPanel()
{ }
virtual ~IPropertiesPanel()
virtual QString displayName() const = 0;
virtual QIcon icon() const = 0;
virtual QWidget *widget() const = 0;
- virtual PanelFlags flags() const { return NoFlag; }
};
class PROJECTEXPLORER_EXPORT IPanelFactory : public QObject
**************************************************************************/
#include "miniprojecttargetselector.h"
+#include "buildconfigurationmodel.h"
+#include "runconfigurationmodel.h"
#include <utils/qtcassert.h>
#include <utils/styledbar.h>
#include <QtGui/QStackedWidget>
#include <QtGui/QKeyEvent>
#include <QtGui/QPainter>
+#include <QtGui/QAction>
#include <QtGui/QItemDelegate>
#include <QtGui/QApplication>
m_buildComboBox->setProperty("hideborder", true);
m_buildComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
m_buildComboBox->setToolTip(tr("Select active build configuration"));
+ m_buildComboBox->setModel(new BuildConfigurationModel(m_target, this));
} else {
m_buildComboBox = 0;
}
m_runComboBox ->setProperty("hideborder", true);
m_runComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
m_runComboBox->setToolTip(tr("Select active run configuration"));
+ RunConfigurationModel *model = new RunConfigurationModel(m_target, this);
+ m_runComboBox->setModel(model);
int fontSize = font().pointSize();
setStyleSheet(QString::fromLatin1("QLabel { font-size: %2pt; color: white; } "
"#target { font: bold %1pt;} "
Q_FOREACH(BuildConfiguration* bc, m_target->buildConfigurations())
addBuildConfiguration(bc);
+ BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildComboBox->model());
+ m_buildComboBox->setCurrentIndex(model->indexFor(m_target->activeBuildConfiguration()).row());
+
connect(m_target, SIGNAL(addedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
SLOT(addBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
connect(m_target, SIGNAL(removedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
connect(m_buildComboBox, SIGNAL(currentIndexChanged(int)), SLOT(setActiveBuildConfiguration(int)));
}
- Q_FOREACH(RunConfiguration* rc, m_target->runConfigurations())
- addRunConfiguration(rc);
+ m_runComboBox->setEnabled(m_target->runConfigurations().count() > 1);
+ m_runComboBox->setCurrentIndex(model->indexFor(m_target->activeRunConfiguration()).row());
connect(m_target, SIGNAL(addedRunConfiguration(ProjectExplorer::RunConfiguration*)),
SLOT(addRunConfiguration(ProjectExplorer::RunConfiguration*)));
void MiniTargetWidget::setActiveBuildConfiguration(int index)
{
- ProjectExplorer::BuildConfiguration* bc =
- m_buildComboBox->itemData(index).value<ProjectExplorer::BuildConfiguration*>();
- m_target->setActiveBuildConfiguration(bc);
+ BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildComboBox->model());
+ m_target->setActiveBuildConfiguration(model->buildConfigurationAt(index));
emit changed();
}
void MiniTargetWidget::setActiveRunConfiguration(int index)
{
- m_target->setActiveRunConfiguration(
- m_runComboBox->itemData(index).value<ProjectExplorer::RunConfiguration*>());
+ RunConfigurationModel *model = static_cast<RunConfigurationModel *>(m_runComboBox->model());
+ m_target->setActiveRunConfiguration(model->runConfigurationAt(index));
updateIcon();
emit changed();
}
+
void MiniTargetWidget::setActiveBuildConfiguration()
{
- QTC_ASSERT(m_buildComboBox, return)
- m_buildComboBox->setCurrentIndex(m_buildComboBox->findData(
- QVariant::fromValue(m_target->activeBuildConfiguration())));
+ QTC_ASSERT(m_buildComboBox, return);
+ BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildComboBox->model());
+ m_buildComboBox->setCurrentIndex(model->indexFor(m_target->activeBuildConfiguration()).row());
}
void MiniTargetWidget::setActiveRunConfiguration()
{
- m_runComboBox->setCurrentIndex(m_runComboBox->findData(
- QVariant::fromValue(m_target->activeRunConfiguration())));
+ RunConfigurationModel *model = static_cast<RunConfigurationModel *>(m_runComboBox->model());
+ m_runComboBox->setCurrentIndex(model->indexFor(m_target->activeRunConfiguration()).row());
}
void MiniTargetWidget::addRunConfiguration(ProjectExplorer::RunConfiguration* rc)
{
- connect(rc, SIGNAL(displayNameChanged()), SLOT(updateDisplayName()));
- m_runComboBox->addItem(rc->displayName(), QVariant::fromValue(rc));
- m_runComboBox->setItemData(m_runComboBox->findText(rc->displayName()),
- rc->displayName(), Qt::ToolTipRole);
- if (m_target->activeRunConfiguration() == rc)
- m_runComboBox->setCurrentIndex(m_runComboBox->count()-1);
-
- m_runComboBox->setEnabled(m_runComboBox->count()>1);
+ Q_UNUSED(rc);
+ m_runComboBox->setEnabled(m_target->runConfigurations().count()>1);
}
void MiniTargetWidget::removeRunConfiguration(ProjectExplorer::RunConfiguration* rc)
{
- m_runComboBox->removeItem(m_runComboBox->findData(QVariant::fromValue(rc)));
- m_runComboBox->setEnabled(m_runComboBox->count()>1);
+ Q_UNUSED(rc);
+ m_runComboBox->setEnabled(m_target->runConfigurations().count()>1);
}
void MiniTargetWidget::addBuildConfiguration(ProjectExplorer::BuildConfiguration* bc)
{
- QTC_ASSERT(m_buildComboBox, return);
- connect(bc, SIGNAL(displayNameChanged()), SLOT(updateDisplayName()));
- m_buildComboBox->addItem(bc->displayName(), QVariant::fromValue(bc));
- m_buildComboBox->setItemData(m_buildComboBox->findText(bc->displayName()),
- bc->displayName(), Qt::ToolTipRole);
- if (m_target->activeBuildConfiguration() == bc)
- m_buildComboBox->setCurrentIndex(m_buildComboBox->count()-1);
-
- m_buildComboBox->setEnabled(m_buildComboBox->count() > 1);
+ Q_UNUSED(bc);
+ connect(bc, SIGNAL(displayNameChanged()), SIGNAL(changed()), Qt::UniqueConnection);
+ m_buildComboBox->setEnabled(m_target->buildConfigurations().count() > 1);
}
void MiniTargetWidget::removeBuildConfiguration(ProjectExplorer::BuildConfiguration* bc)
{
+ Q_UNUSED(bc);
QTC_ASSERT(m_buildComboBox, return);
- m_buildComboBox->removeItem(m_buildComboBox->findData(QVariant::fromValue(bc)));
- m_buildComboBox->setEnabled(m_buildComboBox->count() > 1);
-}
-
-void MiniTargetWidget::updateDisplayName()
-{
- QObject *obj = sender();
- RunConfiguration *rc = qobject_cast<RunConfiguration*>(obj);
- BuildConfiguration *bc = qobject_cast<BuildConfiguration*>(obj);
- if (rc) {
- m_runComboBox->setItemText(m_runComboBox->findData(QVariant::fromValue(rc)),
- rc->displayName());
- } else if (bc) {
- m_buildComboBox->setItemText(m_buildComboBox->findData(QVariant::fromValue(bc)),
- bc->displayName());
- }
- emit changed();
+ m_buildComboBox->setEnabled(m_target->buildConfigurations().count() > 1);
}
bool MiniTargetWidget::hasBuildConfiguration() const
private slots:
void addRunConfiguration(ProjectExplorer::RunConfiguration *runConfig);
- void removeRunConfiguration(ProjectExplorer::RunConfiguration *buildConfig);
+ void removeRunConfiguration(ProjectExplorer::RunConfiguration *runConfig);
void addBuildConfiguration(ProjectExplorer::BuildConfiguration *buildConfig);
void removeBuildConfiguration(ProjectExplorer::BuildConfiguration *buildConfig);
void setActiveBuildConfiguration();
void setActiveRunConfiguration();
- void updateDisplayName();
void updateIcon();
signals:
#include "projectexplorer.h"
#include "projectexplorersettings.h"
#include "runconfiguration.h"
+#include "session.h"
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/actioncontainer.h>
OutputPane::OutputPane()
: m_mainWidget(new QWidget)
{
- QIcon runIcon(Constants::ICON_RUN);
- runIcon.addFile(Constants::ICON_RUN_SMALL);
+ m_runIcon.addFile(Constants::ICON_RUN);
+ m_runIcon.addFile(Constants::ICON_RUN_SMALL);
+
+ m_debugIcon.addFile(Constants::ICON_DEBUG);
+ m_debugIcon.addFile(Constants::ICON_DEBUG_SMALL);
// Rerun
m_reRunButton = new QToolButton;
- m_reRunButton->setIcon(runIcon);
+ m_reRunButton->setIcon(m_runIcon);
m_reRunButton->setToolTip(tr("Re-run this run-configuration"));
m_reRunButton->setAutoRaise(true);
m_reRunButton->setEnabled(false);
connect(Core::ICore::instance(), SIGNAL(coreAboutToClose()),
this, SLOT(coreAboutToClose()));
+
+ connect(ProjectExplorer::ProjectExplorerPlugin::instance()->session(), SIGNAL(aboutToUnloadSession()),
+ this, SLOT(aboutToUnloadSession()));
}
void OutputPane::coreAboutToClose()
}
}
+void OutputPane::aboutToUnloadSession()
+{
+ int i = 0;
+ while (i < m_tabWidget->count()) {
+ bool closed = closeTab(i);
+ if (!closed) // skip to next one
+ ++i;
+ }
+}
+
OutputPane::~OutputPane()
{
delete m_mainWidget;
rc->stop();
}
-void OutputPane::closeTab(int index)
+bool OutputPane::closeTab(int index)
{
OutputWindow *ow = static_cast<OutputWindow *>(m_tabWidget->widget(index));
RunControl *rc = m_outputWindows.key(ow);
if (rc->isRunning()) {
QMessageBox messageBox(QMessageBox::Warning,
tr("Unable to close"),
- tr("The application is still running."),
+ tr("%1 is still running.").arg(rc->displayName()),
QMessageBox::Cancel | QMessageBox::Yes,
ow->window());
messageBox.setInformativeText(tr("Force it to quit?"));
messageBox.setDefaultButton(QMessageBox::Yes);
messageBox.button(QMessageBox::Yes)->setText(tr("Force Quit"));
+ messageBox.button(QMessageBox::Cancel)->setText(tr("Keep Running"));
if (messageBox.exec() != QMessageBox::Yes)
- return;
+ return false;
rc->stop();
}
m_tabWidget->removeTab(index);
delete ow;
delete rc;
+ return true;
}
void OutputPane::projectRemoved()
RunControl *rc = runControlForTab(i);
m_stopAction->setEnabled(rc->isRunning());
m_reRunButton->setEnabled(!rc->isRunning());
+ m_reRunButton->setIcon(rc->runMode() == Constants::DEBUGMODE ? m_debugIcon : m_runIcon);
}
}
if (rc == qobject_cast<RunControl *>(sender())) {
m_reRunButton->setEnabled(false);
m_stopAction->setEnabled(true);
+ m_reRunButton->setIcon(rc->runMode() == Constants::DEBUGMODE ? m_debugIcon : m_runIcon);
}
}
if (rc == qobject_cast<RunControl *>(sender())) {
m_reRunButton->setEnabled(rc);
m_stopAction->setEnabled(false);
+ m_reRunButton->setIcon(rc->runMode() == Constants::DEBUGMODE ? m_debugIcon : m_runIcon);
}
}
#include <QtCore/QObject>
#include <QtCore/QHash>
+#include <QtGui/QIcon>
#include <QtGui/QShowEvent>
#include <QtGui/QPlainTextEdit>
private slots:
void reRunRunControl();
void stopRunControl();
- void closeTab(int index);
+ bool closeTab(int index);
void tabChanged(int);
void runControlStarted();
void runControlFinished();
+ void aboutToUnloadSession();
+
private:
RunControl *runControlForTab(int index) const;
QAction *m_stopAction;
QToolButton *m_reRunButton;
QToolButton *m_stopButton;
+ QIcon m_runIcon;
+ QIcon m_debugIcon;
};
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;
}
globalcontext);
mfilec->addAction(cmd, Constants::G_FILE_OTHER);
- // renamefile action (TODO: Not supported yet)
+ // renamefile action
d->m_renameFileAction = new QAction(tr("Rename"), this);
cmd = am->registerAction(d->m_renameFileAction, ProjectExplorer::Constants::RENAMEFILE,
globalcontext);
mfilec->addAction(cmd, Constants::G_FILE_OTHER);
- d->m_renameFileAction->setEnabled(false);
- d->m_renameFileAction->setVisible(false);
+ // Not yet used by anyone, so hide for now
+// mfolder->addAction(cmd, Constants::G_FOLDER_FILES);
+// msubProject->addAction(cmd, Constants::G_FOLDER_FILES);
+// mproject->addAction(cmd, Constants::G_FOLDER_FILES);
// target selector
d->m_projectSelectorAction = new QAction(this);
QSettings *s = Core::ICore::instance()->settings();
if (s) {
- s->setValue("ProjectExplorer/StartupSession", d->m_session->file()->fileName());
+ s->setValue("ProjectExplorer/StartupSession", d->m_session->currentSession());
s->remove("ProjectExplorer/RecentProjects/Files");
QStringList fileNames;
contextMenu = d->m_sessionContextMenu;
}
- updateContextMenuActions();
+ updateContextMenuActions(d->m_currentNode);
if (contextMenu && contextMenu->actions().count() > 0) {
contextMenu->popup(globalPos);
}
bool ProjectExplorerPlugin::hasBuildSettings(Project *pro)
{
const QList<Project *> & projects = d->m_session->projectOrder(pro);
- foreach(Project *pro, projects)
- if (pro->activeTarget()->activeBuildConfiguration())
+ foreach(Project *project, projects)
+ if (project->activeTarget()->activeBuildConfiguration())
return true;
return false;
}
const QList<Project *> & projects = d->m_session->projectOrder(pro);
QList<BuildConfiguration *> configurations;
- foreach(Project *pro, projects)
- if (pro->activeTarget()->activeBuildConfiguration())
- configurations << pro->activeTarget()->activeBuildConfiguration();
+ foreach(Project *project, projects)
+ if (project->activeTarget()->activeBuildConfiguration())
+ configurations << project->activeTarget()->activeBuildConfiguration();
d->m_buildManager->buildProjects(configurations);
updateRunActions();
d->m_buildManager->gotoTaskWindow();
}
-void ProjectExplorerPlugin::updateContextMenuActions()
+void ProjectExplorerPlugin::updateContextMenuActions(Node *node)
{
d->m_addExistingFilesAction->setEnabled(false);
d->m_addNewFileAction->setEnabled(false);
d->m_removeFileAction->setEnabled(false);
- if (FolderNode *folderNode = qobject_cast<FolderNode*>(d->m_currentNode)) {
- const bool addFilesEnabled = folderNode->projectNode()->supportedActions().contains(ProjectNode::AddFile);
+ QList<ProjectNode::ProjectAction> actions =
+ d->m_currentNode->projectNode()->supportedActions(node);
+
+ if (qobject_cast<FolderNode*>(d->m_currentNode)) {
+ bool addFilesEnabled = actions.contains(ProjectNode::AddFile);
d->m_addExistingFilesAction->setEnabled(addFilesEnabled);
d->m_addNewFileAction->setEnabled(addFilesEnabled);
- } else if (FileNode *fileNode = qobject_cast<FileNode*>(d->m_currentNode)) {
- const bool removeFileEnabled = fileNode->projectNode()->supportedActions().contains(ProjectNode::RemoveFile);
+ d->m_renameFileAction->setEnabled(actions.contains(ProjectNode::Rename));
+ } else if (qobject_cast<FileNode*>(d->m_currentNode)) {
+ bool removeFileEnabled = actions.contains(ProjectNode::RemoveFile);
d->m_removeFileAction->setEnabled(removeFileEnabled);
+ d->m_renameFileAction->setEnabled(actions.contains(ProjectNode::Rename));
}
}
FileNode *fileNode = qobject_cast<FileNode*>(d->m_currentNode);
Core::ICore *core = Core::ICore::instance();
- const QString filePath = d->m_currentNode->path();
- const QString fileDir = QFileInfo(filePath).dir().absolutePath();
+ QString filePath = d->m_currentNode->path();
RemoveFileDialog removeFileDialog(filePath, core->mainWindow());
if (removeFileDialog.exec() == QDialog::Accepted) {
}
}
+void ProjectExplorerPlugin::renameFile(Node *node, const QString &to)
+{
+ FileNode *fileNode = qobject_cast<FileNode *>(node);
+ if (!fileNode)
+ return;
+ QString orgFilePath = node->path();
+ QString dir = QFileInfo(orgFilePath).absolutePath();
+ QString newFilePath = dir + "/" + to;
+ Core::ICore *core = Core::ICore::instance();
+ Core::IVersionControl *vc = core->vcsManager()->findVersionControlForDirectory(dir);
+ bool result = false;
+ if (vc && vc->supportsOperation(Core::IVersionControl::MoveOperation))
+ result = vc->vcsMove(orgFilePath, newFilePath);
+ if (!result) // The moving via vcs failed or the vcs does not support moving, fall back
+ result = QFile::rename(orgFilePath, newFilePath);
+ if (result) {
+ // yeah we moved, tell the filemanager about it
+ Core::ICore::instance()->fileManager()->renamedFile(orgFilePath, newFilePath);
+ // Tell the project plugin about it
+ ProjectNode *projectNode = fileNode->projectNode();
+ projectNode->renameFile(fileNode->fileType(), orgFilePath, newFilePath);
+ // TODO emit a signal?
+ }
+}
+
void ProjectExplorerPlugin::populateOpenWithMenu(QMenu *menu, const QString &fileName)
{
typedef QList<Core::IEditorFactory*> EditorFactoryList;
void startRunControl(RunControl *runControl, const QString &mode);
+ // internal public for FlatModel
+ void renameFile(Node *node, const QString &to);
+
signals:
void aboutToShowContextMenu(ProjectExplorer::Project *project,
ProjectExplorer::Node *node);
void savePersistentSettings();
void goToTaskWindow();
- void updateContextMenuActions();
+ void updateContextMenuActions(Node *node);
void addNewFile();
void addExistingFiles();
void openFile();
TEMPLATE = lib
TARGET = ProjectExplorer
QT += xml \
- script
+ script \
+ network
include(../../qtcreatorplugin.pri)
include(projectexplorer_dependencies.pri)
include(../../shared/scriptwrapper/scriptwrapper.pri)
buildsettingspropertiespage.h \
environmenteditmodel.h \
processstep.h \
- abstractprocessstep.h \
editorconfiguration.h \
editorsettingspropertiespage.h \
runconfiguration.h \
buildconfigdialog.h \
ldparser.h \
linuxiccparser.h \
- outputformatter.h
+ outputformatter.h \
+ runconfigurationmodel.h \
+ buildconfigurationmodel.h \
+ abstractprocessstep.h
SOURCES += projectexplorer.cpp \
projectwindow.cpp \
buildmanager.cpp \
buildconfigdialog.cpp \
ldparser.cpp \
linuxiccparser.cpp \
- outputformatter.cpp
+ outputformatter.cpp \
+ runconfigurationmodel.cpp \
+ buildconfigurationmodel.cpp
FORMS += processstep.ui \
editorsettingspropertiespage.ui \
runsettingspropertiespage.ui \
namespace Internal {
-// AllProjectNodesVisitor: Retrieve all projects (*.pri/*.pro).
+// AllProjectNodesVisitor: Retrieve all projects (*.pri/*.pro)
+// which support adding files
class AllProjectNodesVisitor : public NodesVisitor
{
public:
void AllProjectNodesVisitor::visitProjectNode(ProjectNode *node)
{
- if (node->supportedActions().contains(ProjectNode::AddFile))
+ if (node->supportedActions(node).contains(ProjectNode::AddFile))
m_projectNodes.push_back(node);
}
// duplicate base names in differing directories).
//: No project selected
QStringList projectChoices(tr("<None>"));
- QStringList projectToolTips( QString::null ); // Do not use QString() - gcc-bug.
+ QStringList projectToolTips((QString()));
if (enabled) {
typedef QMap<ProjectEntry, bool> ProjectEntryMap;
// Sort by base name and purge duplicated entries (resulting from dependencies)
typeFileMap.insert(typeForFileName(mdb, path), path);
}
foreach (FileType type, typeFileMap.uniqueKeys()) {
- const QStringList files = typeFileMap.values(type);
- if (!project->addFiles(type, files)) {
+ const QStringList typeFiles = typeFileMap.values(type);
+ if (!project->addFiles(type, typeFiles)) {
*errorMessage = tr("Failed to add one or more files to project\n'%1' (%2).").
- arg(project->path(), files.join(QString(QLatin1Char(','))));
+ arg(project->path(), typeFiles.join(QString(QLatin1Char(','))));
return false;
}
}
#include "project.h"
#include "projectexplorerconstants.h"
#include "projectnodes.h"
+#include "projectexplorer.h"
#include <coreplugin/fileiconprovider.h>
#include <utils/qtcassert.h>
const QString fileName2 = QFileInfo(file2->path()).fileName();
if (fileName1 != fileName2)
- return fileName1 < fileName2;
+ return fileName1.compare(fileName2, Qt::CaseInsensitive) < 0;
else
return file1 < file2;
} else {
ProjectNode *project2 = static_cast<ProjectNode*>(n2);
if (project1->displayName() != project2->displayName())
- return project1->displayName() < project2->displayName(); // sort by name
+ return project1->displayName().compare(project2->displayName(), Qt::CaseInsensitive) < 0; // sort by name
else
return project1 < project2; // sort by pointer value
} else {
FolderNode *folder2 = static_cast<FolderNode*>(n2);
if (folder1->displayName() != folder2->displayName())
- return folder1->displayName() < folder2->displayName();
+ return folder1->displayName().compare(folder2->displayName(), Qt::CaseInsensitive) < 0;
else
return folder1 < folder2;
} else {
const QString fileName2 = QFileInfo(filePath2).fileName();
if (fileName1 != fileName2) {
- return fileName1 < fileName2; // sort by file names
+ return fileName1.compare(fileName2, Qt::CaseInsensitive) < 0; // sort by file names
} else {
if (filePath1 != filePath2) {
- return filePath1 < filePath2; // sort by path names
+ return filePath1.compare(filePath2, Qt::CaseInsensitive) < 0; // sort by path names
} else {
return n1 < n2; // sort by pointer value
}
return result;
}
+Qt::ItemFlags FlatModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return 0;
+ // We claim that everything is editable
+ // That's slightly wrong
+ // We control the only view, and that one does the checks
+ return Qt::ItemIsSelectable|Qt::ItemIsEnabled | Qt::ItemIsEditable;
+}
+
+bool FlatModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (!index.isValid())
+ return false;
+ if (role != Qt::EditRole)
+ return false;
+
+ ProjectExplorerPlugin::instance()->renameFile(nodeForIndex(index), value.toString());
+ return true;
+}
+
int FlatModel::rowCount(const QModelIndex &parent) const
{
int rows = 0;
namespace Internal {
-class FlatModel : public QAbstractItemModel {
+class FlatModel : public QAbstractItemModel
+{
Q_OBJECT
public:
FlatModel(SessionNode *rootNode, QObject *parent);
QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &index) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role);
int rowCount(const QModelIndex & parent = QModelIndex()) const;
int columnCount(const QModelIndex & parent = QModelIndex()) const;
emit watcher->foldersAboutToBeAdded(this, folderNodes);
foreach (ProjectNode *project, subProjects) {
- QTC_ASSERT(!project->parentFolderNode(),
- qDebug("Project node has already a parent"));
+ QTC_ASSERT(!project->parentFolderNode() || project->parentFolderNode() == this,
+ qDebug("Project node has already a parent"));
project->setParentFolderNode(this);
foreach (NodesWatcher *watcher, m_watchers)
project->registerWatcher(watcher);
AddSubProject,
RemoveSubProject,
AddFile,
- RemoveFile
+ RemoveFile,
+ Rename
};
// all subFolders that are projects
// TODO find a better name
virtual bool hasBuildTargets() const = 0;
- virtual QList<ProjectAction> supportedActions() const = 0;
+ virtual QList<ProjectAction> supportedActions(Node *node) const = 0;
virtual bool addSubProjects(const QStringList &proFilePaths) = 0;
void PanelsWidget::addPanelWidget(IPropertiesPanel *panel, int row)
{
QWidget *widget = panel->widget();
- int leftMargin = (panel->flags() & IPropertiesPanel::NoLeftMargin)
- ? 0 : Constants::PANEL_LEFT_MARGIN;
- widget->setContentsMargins(leftMargin,
+ widget->setContentsMargins(Constants::PANEL_LEFT_MARGIN,
ABOVE_CONTENTS_MARGIN, 0,
BELOW_CONTENTS_MARGIN);
widget->setParent(m_root);
{
}
-RunControl::RunControl(RunConfiguration *runConfiguration)
- : m_runConfiguration(runConfiguration)
+RunControl::RunControl(RunConfiguration *runConfiguration, QString mode)
+ : m_runMode(mode), m_runConfiguration(runConfiguration)
{
if (runConfiguration)
m_displayName = runConfiguration->displayName();
}
+QString RunControl::runMode() const
+{
+ return m_runMode;
+}
+
QString RunControl::displayName() const
{
return m_displayName;
{
Q_OBJECT
public:
- explicit RunControl(RunConfiguration *runConfiguration);
+ explicit RunControl(RunConfiguration *runConfiguration, QString mode);
virtual ~RunControl();
virtual void start() = 0;
virtual void stop() = 0; // Warning: assumed to be synchroneous!
bool sameRunConfiguration(RunControl *other);
virtual OutputFormatter *createOutputFormatter(QObject *parent = 0);
+ QString runMode() const;
signals:
void addToOutputWindow(RunControl *, const QString &line, bool onStdErr);
private:
QString m_displayName;
+ QString m_runMode;
const QWeakPointer<RunConfiguration> m_runConfiguration;
#ifdef Q_OS_MAC
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "runconfigurationmodel.h"
+#include "target.h"
+#include "runconfiguration.h"
+
+using namespace ProjectExplorer;
+
+///
+/// RunConfigurationsModel
+///
+
+class RunConfigurationComparer
+{
+public:
+ bool operator()(RunConfiguration *a, RunConfiguration *b)
+ {
+ return a->displayName() < b->displayName();
+ }
+};
+
+RunConfigurationModel::RunConfigurationModel(Target *target, QObject *parent)
+ : QAbstractListModel(parent),
+ m_target(target)
+{
+ m_runConfigurations = m_target->runConfigurations();
+ qSort(m_runConfigurations.begin(), m_runConfigurations.end(), RunConfigurationComparer());
+
+ connect(target, SIGNAL(addedRunConfiguration(ProjectExplorer::RunConfiguration*)),
+ this, SLOT(addedRunConfiguration(ProjectExplorer::RunConfiguration*)));
+ connect(target, SIGNAL(removedRunConfiguration(ProjectExplorer::RunConfiguration*)),
+ this, SLOT(removedRunConfiguration(ProjectExplorer::RunConfiguration*)));
+
+ foreach (RunConfiguration *rc, m_runConfigurations)
+ connect(rc, SIGNAL(displayNameChanged()),
+ this, SLOT(displayNameChanged()));
+}
+
+int RunConfigurationModel::rowCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? 0 : m_runConfigurations.size();
+}
+
+int RunConfigurationModel::columnCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? 0 : 1;
+}
+
+void RunConfigurationModel::displayNameChanged()
+{
+ RunConfiguration *rc = qobject_cast<RunConfiguration *>(sender());
+ if (!rc)
+ return;
+
+ RunConfigurationComparer compare;
+ // Find the old position
+ int oldPos = m_runConfigurations.indexOf(rc);
+
+ if (oldPos >= 1 && compare(m_runConfigurations.at(oldPos), m_runConfigurations.at(oldPos - 1))) {
+ // We need to move up
+ int newPos = oldPos - 1;
+ while (newPos >= 0 && compare(m_runConfigurations.at(oldPos), m_runConfigurations.at(newPos))) {
+ --newPos;
+ }
+ ++newPos;
+
+ beginMoveRows(QModelIndex(), oldPos, oldPos, QModelIndex(), newPos);
+ m_runConfigurations.insert(newPos, rc);
+ m_runConfigurations.removeAt(oldPos + 1);
+ endMoveRows();
+ // Not only did we move, we also changed...
+ emit dataChanged(index(newPos, 0), index(newPos,0));
+ } else if (oldPos < m_runConfigurations.size() - 1
+ && compare(m_runConfigurations.at(oldPos + 1), m_runConfigurations.at(oldPos))) {
+ // We need to move down
+ int newPos = oldPos + 1;
+ while (newPos < m_runConfigurations.size()
+ && compare(m_runConfigurations.at(newPos), m_runConfigurations.at(oldPos))) {
+ ++newPos;
+ }
+ beginMoveRows(QModelIndex(), oldPos, oldPos, QModelIndex(), newPos);
+ m_runConfigurations.insert(newPos, rc);
+ m_runConfigurations.removeAt(oldPos);
+ endMoveRows();
+
+ // We need to subtract one since removing at the old place moves the newIndex down
+ emit dataChanged(index(newPos - 1, 0), index(newPos - 1, 0));
+ } else {
+ emit dataChanged(index(oldPos, 0), index(oldPos, 0));
+ }
+}
+
+QVariant RunConfigurationModel::data(const QModelIndex &index, int role) const
+{
+ if (role == Qt::DisplayRole) {
+ const int row = index.row();
+ if (row < m_runConfigurations.size()) {
+ return m_runConfigurations.at(row)->displayName();
+ }
+ }
+
+ return QVariant();
+}
+
+RunConfiguration *RunConfigurationModel::runConfigurationAt(int i)
+{
+ if (i > m_runConfigurations.size() || i < 0)
+ return 0;
+ return m_runConfigurations.at(i);
+}
+
+RunConfiguration *RunConfigurationModel::runConfigurationFor(const QModelIndex &idx)
+{
+ if (idx.row() > m_runConfigurations.size() || idx.row() < 0)
+ return 0;
+ return m_runConfigurations.at(idx.row());
+}
+
+QModelIndex RunConfigurationModel::indexFor(RunConfiguration *rc)
+{
+ int idx = m_runConfigurations.indexOf(rc);
+ if (idx == -1)
+ return QModelIndex();
+ return index(idx, 0);
+}
+
+void RunConfigurationModel::addedRunConfiguration(ProjectExplorer::RunConfiguration *rc)
+{
+ // Find the right place to insert
+ RunConfigurationComparer compare;
+ int i = 0;
+ for (; i < m_runConfigurations.size(); ++i) {
+ if (compare(rc, m_runConfigurations.at(i))) {
+ break;
+ }
+ }
+
+ beginInsertRows(QModelIndex(), i, i);
+ m_runConfigurations.insert(i, rc);
+ endInsertRows();
+
+
+ connect(rc, SIGNAL(displayNameChanged()),
+ this, SLOT(displayNameChanged()));
+}
+
+void RunConfigurationModel::removedRunConfiguration(ProjectExplorer::RunConfiguration *rc)
+{
+ int i = m_runConfigurations.indexOf(rc);
+ beginRemoveRows(QModelIndex(), i, i);
+ m_runConfigurations.removeAt(i);
+ endRemoveRows();
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef RUNCONFIGURATIONMODEL_H
+#define RUNCONFIGURATIONMODEL_H
+
+#include <QtCore/QAbstractItemModel>
+
+namespace ProjectExplorer {
+class Target;
+class RunConfiguration;
+
+/*! A model to represent the run configurations of a target.
+ To be used in for the drop down of comboboxes
+ Does automatically adjust itself to added and removed RunConfigurations
+*/
+class RunConfigurationModel : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+ RunConfigurationModel(Target *target, QObject *parent = 0);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+ RunConfiguration *runConfigurationAt(int i);
+ RunConfiguration *runConfigurationFor(const QModelIndex &idx);
+ QModelIndex indexFor(RunConfiguration *rc);
+private slots:
+ void addedRunConfiguration(ProjectExplorer::RunConfiguration*);
+ void removedRunConfiguration(ProjectExplorer::RunConfiguration*);
+ void displayNameChanged();
+private:
+ Target *m_target;
+ QList<RunConfiguration *> m_runConfigurations;
+};
+
+}
+
+#endif // RUNCONFIGURATIONMODEL_H
**************************************************************************/
#include "runsettingspropertiespage.h"
+#include "runconfigurationmodel.h"
#include "runconfiguration.h"
#include "target.h"
#include "project.h"
}
///
-/// RunConfigurationsModel
-///
-
-RunConfigurationsModel::RunConfigurationsModel(Target *target, QObject *parent)
- : QAbstractListModel(parent),
- m_target(target)
-{
- m_runConfigurations = m_target->runConfigurations();
- connect(target, SIGNAL(addedRunConfiguration(ProjectExplorer::RunConfiguration*)),
- this, SLOT(addedRunConfiguration(ProjectExplorer::RunConfiguration*)));
- connect(target, SIGNAL(removedRunConfiguration(ProjectExplorer::RunConfiguration*)),
- this, SLOT(removedRunConfiguration(ProjectExplorer::RunConfiguration*)));
-
- foreach (RunConfiguration *rc, m_runConfigurations)
- connect(rc, SIGNAL(displayNameChanged()),
- this, SLOT(displayNameChanged()));
-}
-
-int RunConfigurationsModel::rowCount(const QModelIndex &parent) const
-{
- return parent.isValid() ? 0 : m_runConfigurations.size();
-}
-
-int RunConfigurationsModel::columnCount(const QModelIndex &parent) const
-{
- return parent.isValid() ? 0 : 1;
-}
-
-void RunConfigurationsModel::displayNameChanged()
-{
- RunConfiguration *rc = qobject_cast<RunConfiguration *>(sender());
- QTC_ASSERT(rc, return);
- for (int i = 0; i < m_runConfigurations.size(); ++i) {
- if (m_runConfigurations.at(i) == rc) {
- emit dataChanged(index(i, 0), index(i,0));
- break;
- }
- }
-}
-
-QVariant RunConfigurationsModel::data(const QModelIndex &index, int role) const
-{
- if (role == Qt::DisplayRole) {
- const int row = index.row();
- if (row < m_runConfigurations.size()) {
- return m_runConfigurations.at(row)->displayName();
- }
- }
-
- return QVariant();
-}
-
-RunConfiguration *RunConfigurationsModel::runConfigurationAt(int i)
-{
- if (i > m_runConfigurations.size() || i < 0)
- return 0;
- return m_runConfigurations.at(i);
-}
-
-RunConfiguration *RunConfigurationsModel::runConfigurationFor(const QModelIndex &idx)
-{
- if (idx.row() > m_runConfigurations.size() || idx.row() < 0)
- return 0;
- return m_runConfigurations.at(idx.row());
-}
-
-QModelIndex RunConfigurationsModel::indexFor(RunConfiguration *rc)
-{
- int idx = m_runConfigurations.indexOf(rc);
- if (idx == -1)
- return QModelIndex();
- return index(idx, 0);
-}
-
-void RunConfigurationsModel::addedRunConfiguration(ProjectExplorer::RunConfiguration *rc)
-{
- int i = m_target->runConfigurations().indexOf(rc);
- QTC_ASSERT(i > 0, return);
- beginInsertRows(QModelIndex(), i, i);
- m_runConfigurations.insert(i, rc);
- endInsertRows();
- QTC_ASSERT(m_runConfigurations == m_target->runConfigurations(), return);
- connect(rc, SIGNAL(displayNameChanged()),
- this, SLOT(displayNameChanged()));
-}
-
-void RunConfigurationsModel::removedRunConfiguration(ProjectExplorer::RunConfiguration *rc)
-{
- int i = m_runConfigurations.indexOf(rc);
- QTC_ASSERT(i >= 0, return);
- beginRemoveRows(QModelIndex(), i, i);
- m_runConfigurations.removeAt(i);
- endRemoveRows();
- QTC_ASSERT(m_runConfigurations == m_target->runConfigurations(), return);
-}
-
-
-///
/// RunSettingsWidget
///
RunSettingsWidget::RunSettingsWidget(Target *target)
: m_target(target),
- m_runConfigurationsModel(new RunConfigurationsModel(target, this)),
+ m_runConfigurationsModel(new RunConfigurationModel(target, this)),
m_runConfigurationWidget(0),
m_ignoreChange(false)
{
m_ui->removeToolButton->setText(tr("Remove"));
m_ui->runConfigurationCombo->setModel(m_runConfigurationsModel);
m_ui->runConfigurationCombo->setCurrentIndex(
- m_target->runConfigurations().indexOf(m_target->activeRunConfiguration()));
+ m_runConfigurationsModel->indexFor(m_target->activeRunConfiguration()).row());
m_ui->removeToolButton->setEnabled(m_target->runConfigurations().size() > 1);
namespace ProjectExplorer {
class RunConfiguration;
+class RunConfigurationModel;
namespace Internal {
class RunSettingsPropertiesPage;
}
-class RunConfigurationsModel;
class RunSettingsWidget;
class RunSettingsPanelFactory : public ITargetPanelFactory
void activeRunConfigurationChanged();
private:
Target *m_target;
- RunConfigurationsModel *m_runConfigurationsModel;
+ RunConfigurationModel *m_runConfigurationsModel;
Ui::RunSettingsPropertiesPage *m_ui;
QWidget *m_runConfigurationWidget;
QMenu *m_addMenu;
bool m_ignoreChange;
};
-/*! A model to represent the run configurations of a target. */
-class RunConfigurationsModel : public QAbstractListModel
-{
- Q_OBJECT
-public:
- RunConfigurationsModel(Target *target, QObject *parent = 0);
-
- int rowCount(const QModelIndex &parent = QModelIndex()) const;
- int columnCount(const QModelIndex &parent = QModelIndex()) const;
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
-
- RunConfiguration *runConfigurationAt(int i);
- RunConfiguration *runConfigurationFor(const QModelIndex &idx);
- QModelIndex indexFor(RunConfiguration *rc);
-private slots:
- void addedRunConfiguration(ProjectExplorer::RunConfiguration*);
- void removedRunConfiguration(ProjectExplorer::RunConfiguration*);
- void displayNameChanged();
-private:
- Target *m_target;
- QList<RunConfiguration *> m_runConfigurations;
-};
-
-
-
} // namespace Internal
} // namespace ProjectExplorer
namespace ProjectExplorer {
namespace Internal {
-class SessionFile : public Core::IFile
+class SessionFile : QObject
{
Q_OBJECT
QString fileName() const;
void setFileName(const QString &fileName);
- QString defaultPath() const;
- QString suggestedFileName() const;
- virtual QString mimeType() const;
-
- bool isModified() const;
- bool isReadOnly() const;
- bool isSaveAsAllowed() const;
-
- ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
- void reload(ReloadFlag flag, ChangeType type);
-
public slots:
void sessionLoadingProgress();
-
private:
- const QString m_mimeType;
Core::ICore *m_core;
QString m_fileName;
}
SessionFile::SessionFile()
- : m_mimeType(QLatin1String(ProjectExplorer::Constants::SESSIONFILE_MIMETYPE)),
- m_core(Core::ICore::instance()),
+ : m_core(Core::ICore::instance()),
m_startupProject(0)
{
}
-QString SessionFile::mimeType() const
-{
- return m_mimeType;
-}
-
bool SessionFile::load(const QString &fileName)
{
Q_ASSERT(!fileName.isEmpty());
m_fileName = fileName;
}
-bool SessionFile::isModified() const
-{
- return true;
-}
-
-bool SessionFile::isReadOnly() const
-{
- return false;
-}
-
-bool SessionFile::isSaveAsAllowed() const
-{
- return true;
-}
-
-Core::IFile::ReloadBehavior SessionFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
-{
- Q_UNUSED(state)
- Q_UNUSED(type)
- return BehaviorSilent;
-}
-
-void SessionFile::reload(ReloadFlag flag, ChangeType type)
-{
- Q_UNUSED(flag)
- Q_UNUSED(type)
-}
-
-QString SessionFile::defaultPath() const
-{
- if (!m_projects.isEmpty()) {
- const QFileInfo fi(m_projects.first()->file()->fileName());
- return fi.absolutePath();
- }
- return QString();
-}
-
-QString SessionFile::suggestedFileName() const
-{
- if (m_startupProject)
- return m_startupProject->displayName();
-
- return tr("Untitled", "default file name to display");
-}
-
Internal::SessionNodeImpl::SessionNodeImpl(SessionManager *manager)
- : ProjectExplorer::SessionNode(manager->file()->fileName(), manager)
+ : ProjectExplorer::SessionNode(manager->currentSession(), manager)
{
setFileName("session");
}
textEditor->setTextCodec(project->editorConfiguration()->defaultTextCodec());
}
-Core::IFile *SessionManager::file() const
+QString SessionManager::currentSession() const
{
- return m_file;
+ return m_file->fileName();
}
void SessionManager::handleCurrentEditorChange(Core::IEditor *editor)
bool addDependency(Project *project, Project *depProject);
void removeDependency(Project *project, Project *depProject);
- Core::IFile *file() const;
+ QString currentSession() const;
Project *startupProject() const;
const QList<Project *> &projects() const;
#include <QtGui/QStyledItemDelegate>
#include <QtGui/QSortFilterProxyModel>
#include <QtGui/QMenu>
+#include <QtGui/QToolButton>
namespace {
const int TASK_ICON_SIZE = 16;
QStringList m_categoryIds;
};
-} // Internal
-} // ProjectExplorer
-
-
-using namespace ProjectExplorer;
-using namespace ProjectExplorer::Internal;
-
-
-////
-// TaskView
-////
-
TaskView::TaskView(QWidget *parent)
: QListView(parent)
{
return accept;
}
+} // namespace Internal
+
/////
// TaskWindow
/////
+struct TaskWindowPrivate {
+ Internal::TaskModel *m_model;
+ Internal::TaskFilterModel *m_filter;
+ Internal::TaskView *m_listview;
+ Internal::TaskWindowContext *m_taskWindowContext;
+ QAction *m_copyAction;
+ QAction *m_vcsAnnotateAction;
+ QToolButton *m_filterWarningsButton;
+ QToolButton *m_categoriesButton;
+ QMenu *m_categoriesMenu;
+};
+
static QToolButton *createFilterButton(QIcon icon, const QString &toolTip,
QObject *receiver, const char *slot)
{
return button;
}
-TaskWindow::TaskWindow()
+TaskWindow::TaskWindow() : d(new TaskWindowPrivate)
{
Core::ICore *core = Core::ICore::instance();
- m_model = new TaskModel;
- m_filter = new TaskFilterModel(m_model);
- m_listview = new TaskView;
+ d->m_model = new Internal::TaskModel;
+ d->m_filter = new Internal::TaskFilterModel(d->m_model);
+ d->m_listview = new Internal::TaskView;
- m_listview->setModel(m_filter);
- m_listview->setFrameStyle(QFrame::NoFrame);
- m_listview->setWindowTitle(tr("Build Issues"));
- m_listview->setSelectionMode(QAbstractItemView::SingleSelection);
- TaskDelegate *tld = new TaskDelegate(this);
- m_listview->setItemDelegate(tld);
- m_listview->setWindowIcon(QIcon(":/qt4projectmanager/images/window.png"));
- m_listview->setContextMenuPolicy(Qt::ActionsContextMenu);
- m_listview->setAttribute(Qt::WA_MacShowFocusRect, false);
+ d->m_listview->setModel(d->m_filter);
+ d->m_listview->setFrameStyle(QFrame::NoFrame);
+ d->m_listview->setWindowTitle(tr("Build Issues"));
+ d->m_listview->setSelectionMode(QAbstractItemView::SingleSelection);
+ Internal::TaskDelegate *tld = new Internal::TaskDelegate(this);
+ d->m_listview->setItemDelegate(tld);
+ d->m_listview->setWindowIcon(QIcon(":/qt4projectmanager/images/window.png"));
+ d->m_listview->setContextMenuPolicy(Qt::ActionsContextMenu);
+ d->m_listview->setAttribute(Qt::WA_MacShowFocusRect, false);
- m_taskWindowContext = new TaskWindowContext(m_listview);
- core->addContextObject(m_taskWindowContext);
+ d->m_taskWindowContext = new Internal::TaskWindowContext(d->m_listview);
+ core->addContextObject(d->m_taskWindowContext);
- m_copyAction = new QAction(QIcon(Core::Constants::ICON_COPY), tr("&Copy"), this);
+ d->m_copyAction = new QAction(QIcon(Core::Constants::ICON_COPY), tr("&Copy"), this);
Core::Command *command = core->actionManager()->
- registerAction(m_copyAction, Core::Constants::COPY, m_taskWindowContext->context());
- m_listview->addAction(command->action());
- connect(m_copyAction, SIGNAL(triggered()), SLOT(copy()));
+ registerAction(d->m_copyAction, Core::Constants::COPY, d->m_taskWindowContext->context());
+ d->m_listview->addAction(command->action());
+ connect(d->m_copyAction, SIGNAL(triggered()), SLOT(copy()));
// Annotate using VCS: Make visible in all contexts
- m_vcsAnnotateAction = new QAction(tr("&Annotate"), this);
- m_vcsAnnotateAction->setToolTip("Annotate using version control system");
- QList<int> annotateContext = m_taskWindowContext->context();
+ d->m_vcsAnnotateAction = new QAction(tr("&Annotate"), this);
+ d->m_vcsAnnotateAction->setToolTip("Annotate using version control system");
+ QList<int> annotateContext = d->m_taskWindowContext->context();
annotateContext << Core::ICore::instance()->uniqueIDManager()->uniqueIdentifier(QLatin1String(Core::Constants::C_GLOBAL));
command = core->actionManager()->
- registerAction(m_vcsAnnotateAction, QLatin1String("ProjectExplorer.Task.VCS_Annotate"), annotateContext);
- m_listview->addAction(command->action());
- connect(m_vcsAnnotateAction, SIGNAL(triggered()), SLOT(vcsAnnotate()));
+ registerAction(d->m_vcsAnnotateAction, QLatin1String("ProjectExplorer.Task.VCS_Annotate"), annotateContext);
+ d->m_listview->addAction(command->action());
+ connect(d->m_vcsAnnotateAction, SIGNAL(triggered()), SLOT(vcsAnnotate()));
- connect(m_listview->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
+ connect(d->m_listview->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
tld, SLOT(currentChanged(QModelIndex,QModelIndex)));
- connect(m_listview, SIGNAL(activated(QModelIndex)),
+ connect(d->m_listview, SIGNAL(activated(QModelIndex)),
this, SLOT(showTaskInFile(QModelIndex)));
- connect(m_listview, SIGNAL(clicked(QModelIndex)),
+ connect(d->m_listview, SIGNAL(clicked(QModelIndex)),
this, SLOT(showTaskInFile(QModelIndex)));
- m_filterWarningsButton = createFilterButton(taskTypeIcon(Task::Warning),
+ d->m_filterWarningsButton = createFilterButton(taskTypeIcon(Task::Warning),
tr("Show Warnings"),
this, SLOT(setShowWarnings(bool)));
- m_categoriesMenu = new QMenu;
- connect(m_categoriesMenu, SIGNAL(aboutToShow()), this, SLOT(updateCategoriesMenu()));
- connect(m_categoriesMenu, SIGNAL(triggered(QAction*)), this, SLOT(filterCategoryTriggered(QAction*)));
+ d->m_categoriesMenu = new QMenu;
+ connect(d->m_categoriesMenu, SIGNAL(aboutToShow()), this, SLOT(updateCategoriesMenu()));
+ connect(d->m_categoriesMenu, SIGNAL(triggered(QAction*)), this, SLOT(filterCategoryTriggered(QAction*)));
- m_categoriesButton = new QToolButton;
- m_categoriesButton->setIcon(QIcon(":/projectexplorer/images/filtericon.png"));
- m_categoriesButton->setToolTip(tr("Filter by categories"));
- m_categoriesButton->setAutoRaise(true);
- m_categoriesButton->setPopupMode(QToolButton::InstantPopup);
- m_categoriesButton->setMenu(m_categoriesMenu);
+ d->m_categoriesButton = new QToolButton;
+ d->m_categoriesButton->setIcon(QIcon(":/projectexplorer/images/filtericon.png"));
+ d->m_categoriesButton->setToolTip(tr("Filter by categories"));
+ d->m_categoriesButton->setAutoRaise(true);
+ d->m_categoriesButton->setPopupMode(QToolButton::InstantPopup);
+ d->m_categoriesButton->setMenu(d->m_categoriesMenu);
qRegisterMetaType<ProjectExplorer::Task>("ProjectExplorer::Task");
qRegisterMetaType<QList<ProjectExplorer::Task> >("QList<ProjectExplorer::Task>");
TaskWindow::~TaskWindow()
{
- Core::ICore::instance()->removeContextObject(m_taskWindowContext);
- delete m_filterWarningsButton;
- delete m_listview;
- delete m_filter;
- delete m_model;
+ Core::ICore::instance()->removeContextObject(d->m_taskWindowContext);
+ delete d->m_filterWarningsButton;
+ delete d->m_listview;
+ delete d->m_filter;
+ delete d->m_model;
+ delete d;
}
QList<QWidget*> TaskWindow::toolBarWidgets() const
{
- return QList<QWidget*>() << m_filterWarningsButton << m_categoriesButton;
+ return QList<QWidget*>() << d->m_filterWarningsButton << d->m_categoriesButton;
}
QWidget *TaskWindow::outputWidget(QWidget *)
{
- return m_listview;
+ return d->m_listview;
}
void TaskWindow::clearTasks(const QString &categoryId)
{
- m_model->clearTasks(categoryId);
+ d->m_model->clearTasks(categoryId);
updateActions();
emit tasksChanged();
void TaskWindow::addCategory(const QString &categoryId, const QString &displayName)
{
Q_ASSERT(!categoryId.isEmpty());
- m_model->addCategory(categoryId, displayName);
+ d->m_model->addCategory(categoryId, displayName);
}
void TaskWindow::addTask(const Task &task)
{
- m_model->addTask(task);
+ d->m_model->addTask(task);
updateActions();
emit tasksChanged();
void TaskWindow::removeTask(const Task &task)
{
- m_model->removeTask(task);
+ d->m_model->removeTask(task);
updateActions();
emit tasksChanged();
{
if (!index.isValid())
return;
- QString file = index.data(TaskModel::File).toString();
- int line = index.data(TaskModel::Line).toInt();
+ QString file = index.data(Internal::TaskModel::File).toString();
+ int line = index.data(Internal::TaskModel::Line).toInt();
if (file.isEmpty() || line == -1)
return;
Core::EditorManager::instance()->ensureEditorManagerVisible();
}
else
- m_model->setFileNotFound(index, true);
- m_listview->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select);
- m_listview->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
+ d->m_model->setFileNotFound(index, true);
+ d->m_listview->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select);
+ d->m_listview->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
}
// Right-click VCS annotate: Find version control and point it to line
void TaskWindow::vcsAnnotate()
{
- const QModelIndex index = m_listview->selectionModel()->currentIndex();
+ const QModelIndex index = d->m_listview->selectionModel()->currentIndex();
if (!index.isValid())
return;
- const QString file = index.data(TaskModel::File).toString();
- const int line = index.data(TaskModel::Line).toInt();
+ const QString file = index.data(Internal::TaskModel::File).toString();
+ const int line = index.data(Internal::TaskModel::Line).toInt();
const QFileInfo fi(file);
if (fi.exists())
if (Core::IVersionControl *vc = Core::ICore::instance()->vcsManager()->findVersionControlForDirectory(fi.absolutePath()))
void TaskWindow::copy()
{
- const QModelIndex index = m_listview->selectionModel()->currentIndex();
+ const QModelIndex index = d->m_listview->selectionModel()->currentIndex();
if (!index.isValid())
return;
- const QString file = index.data(TaskModel::File).toString();
- const QString line = index.data(TaskModel::Line).toString();
- const QString description = index.data(TaskModel::Description).toString();
+ const QString file = index.data(Internal::TaskModel::File).toString();
+ const QString line = index.data(Internal::TaskModel::Line).toString();
+ const QString description = index.data(Internal::TaskModel::Description).toString();
QString type;
- switch (index.data(TaskModel::Type).toInt()) {
+ switch (index.data(Internal::TaskModel::Type).toInt()) {
case Task::Error:
type = "error: ";
break;
void TaskWindow::setShowWarnings(bool show)
{
- m_filter->setFilterIncludesWarnings(show);
- m_filter->setFilterIncludesUnknowns(show); // "Unknowns" are often associated with warnings
+ d->m_filter->setFilterIncludesWarnings(show);
+ d->m_filter->setFilterIncludesUnknowns(show); // "Unknowns" are often associated with warnings
}
void TaskWindow::updateCategoriesMenu()
{
- m_categoriesMenu->clear();
+ d->m_categoriesMenu->clear();
- const QStringList filteredCategories = m_filter->filteredCategories();
+ const QStringList filteredCategories = d->m_filter->filteredCategories();
- foreach (const QString &categoryId, m_model->categoryIds()) {
- const QString categoryName = m_model->categoryDisplayName(categoryId);
+ foreach (const QString &categoryId, d->m_model->categoryIds()) {
+ const QString categoryName = d->m_model->categoryDisplayName(categoryId);
- QAction *action = new QAction(m_categoriesMenu);
+ QAction *action = new QAction(d->m_categoriesMenu);
action->setCheckable(true);
action->setText(categoryName);
action->setData(categoryId);
action->setChecked(!filteredCategories.contains(categoryId));
- m_categoriesMenu->addAction(action);
+ d->m_categoriesMenu->addAction(action);
}
}
QString categoryId = action->data().toString();
Q_ASSERT(!categoryId.isEmpty());
- QStringList categories = m_filter->filteredCategories();
- Q_ASSERT(m_filter->filteredCategories().contains(categoryId) == action->isChecked());
+ QStringList categories = d->m_filter->filteredCategories();
+ Q_ASSERT(d->m_filter->filteredCategories().contains(categoryId) == action->isChecked());
if (action->isChecked()) {
categories.removeOne(categoryId);
categories.append(categoryId);
}
- m_filter->setFilteredCategories(categories);
+ d->m_filter->setFilteredCategories(categories);
}
int TaskWindow::taskCount() const
{
- return m_model->taskCount();
+ return d->m_model->taskCount();
}
int TaskWindow::errorTaskCount() const
{
- return m_model->errorTaskCount();
+ return d->m_model->errorTaskCount();
}
int TaskWindow::priorityInStatusBar() const
bool TaskWindow::hasFocus()
{
- return m_listview->hasFocus();
+ return d->m_listview->hasFocus();
}
bool TaskWindow::canFocus()
{
- return m_filter->rowCount();
+ return d->m_filter->rowCount();
}
void TaskWindow::setFocus()
{
- if (m_filter->rowCount()) {
- m_listview->setFocus();
- if (m_listview->currentIndex() == QModelIndex()) {
- m_listview->setCurrentIndex(m_filter->index(0,0, QModelIndex()));
+ if (d->m_filter->rowCount()) {
+ d->m_listview->setFocus();
+ if (d->m_listview->currentIndex() == QModelIndex()) {
+ d->m_listview->setCurrentIndex(d->m_filter->index(0,0, QModelIndex()));
}
}
}
bool TaskWindow::canNext()
{
- return m_filter->rowCount();
+ return d->m_filter->rowCount();
}
bool TaskWindow::canPrevious()
{
- return m_filter->rowCount();
+ return d->m_filter->rowCount();
}
void TaskWindow::goToNext()
{
- if (!m_filter->rowCount())
+ if (!d->m_filter->rowCount())
return;
- QModelIndex currentIndex = m_listview->currentIndex();
+ QModelIndex currentIndex = d->m_listview->currentIndex();
if (currentIndex.isValid()) {
int row = currentIndex.row() + 1;
- if (row == m_filter->rowCount())
+ if (row == d->m_filter->rowCount())
row = 0;
- currentIndex = m_filter->index(row, 0);
+ currentIndex = d->m_filter->index(row, 0);
} else {
- currentIndex = m_filter->index(0, 0);
+ currentIndex = d->m_filter->index(0, 0);
}
- m_listview->setCurrentIndex(currentIndex);
+ d->m_listview->setCurrentIndex(currentIndex);
showTaskInFile(currentIndex);
}
void TaskWindow::goToPrev()
{
- if (!m_filter->rowCount())
+ if (!d->m_filter->rowCount())
return;
- QModelIndex currentIndex = m_listview->currentIndex();
+ QModelIndex currentIndex = d->m_listview->currentIndex();
if (currentIndex.isValid()) {
int row = currentIndex.row() -1;
if (row < 0)
- row = m_filter->rowCount() - 1;
- currentIndex = m_filter->index(row, 0);
+ row = d->m_filter->rowCount() - 1;
+ currentIndex = d->m_filter->index(row, 0);
} else {
- currentIndex = m_filter->index(m_filter->rowCount()-1, 0);
+ currentIndex = d->m_filter->index(d->m_filter->rowCount()-1, 0);
}
- m_listview->setCurrentIndex(currentIndex);
+ d->m_listview->setCurrentIndex(currentIndex);
showTaskInFile(currentIndex);
}
void TaskWindow::updateActions()
{
- m_copyAction->setEnabled(m_model->tasks().count() > 0);
+ d->m_copyAction->setEnabled(d->m_model->tasks().count() > 0);
}
QIcon TaskWindow::taskTypeIcon(Task::TaskType t) const
{
- return m_model->taskTypeIcon(t);
+ return d->m_model->taskTypeIcon(t);
}
+namespace Internal {
/////
// Delegate
/////
return m_taskList;
}
+} // namespace Internal
//
// functions
//
-bool ProjectExplorer::operator==(const Task &t1, const Task &t2)
+bool operator==(const Task &t1, const Task &t2)
{
return t1.type == t2.type
&& t1.line == t2.line
&& t1.category == t2.category;
}
-uint ProjectExplorer::qHash(const Task &task)
+uint qHash(const Task &task)
{
return qHash(task.file) + task.line;
}
+} // namespace ProjectExplorer
+
#include "taskwindow.moc"
#include "projectexplorer_export.h"
-#include <coreplugin/icontext.h>
#include <coreplugin/ioutputpane.h>
-#include <QtCore/QModelIndex>
-#include <QtGui/QAction>
-#include <QtGui/QToolButton>
#include <QtGui/QTextLayout>
-namespace ProjectExplorer {
-
-namespace Internal {
-
-class TaskModel;
-class TaskFilterModel;
-class TaskView;
-class TaskWindowContext;
+QT_BEGIN_NAMESPACE
+class QModelIndex;
+QT_END_NAMESPACE
-} // namespace Internal
+namespace ProjectExplorer {
+struct TaskWindowPrivate;
+// Build issue (warning or error).
struct PROJECTEXPLORER_EXPORT Task {
enum TaskType {
Unknown,
QString file;
int line;
QString category;
- // Having a QList<QTextLayout::FormatRange> in Task
- // isn't that great
+ // Having a QList<QTextLayout::FormatRange> in Task isn't that great
// It would be cleaner to split up the text into
// the logical hunks and then assemble them again
- // (That is diffrent consumers of tasks could show them in
+ // (That is different consumers of tasks could show them in
// different ways!)
// But then again, the wording of the text most likely
// doesn't work if you split it up, nor are our parsers
QList<QTextLayout::FormatRange> formats;
};
+struct TaskWindowPrivate;
+
+// Show build issues (warnings or errors) and open the editor on click.
class PROJECTEXPLORER_EXPORT TaskWindow : public Core::IOutputPane
{
Q_OBJECT
public:
TaskWindow();
- ~TaskWindow();
+ virtual ~TaskWindow();
void addCategory(const QString &categoryId, const QString &displayName);
void updateActions();
int sizeHintForColumn(int column) const;
- Internal::TaskModel *m_model;
- Internal::TaskFilterModel *m_filter;
- Internal::TaskView *m_listview;
- Internal::TaskWindowContext *m_taskWindowContext;
- QAction *m_copyAction;
- QAction *m_vcsAnnotateAction;
- QToolButton *m_filterWarningsButton;
- QToolButton *m_categoriesButton;
- QMenu *m_categoriesMenu;
+ TaskWindowPrivate *d;
};
bool operator==(const Task &t1, const Task &t2);
#include "target.h"
#include "toolchain.h"
+#include <coreplugin/icore.h>
+#include <coreplugin/mainwindow.h>
#include <coreplugin/ifile.h>
#include <utils/qtcassert.h>
-#include <QtCore/QCoreApplication>
+#include <QtGui/QApplication>
#include <QtCore/QFile>
+#include <QtGui/QMessageBox>
+#include <QtNetwork/QHostInfo>
using namespace ProjectExplorer;
namespace {
-const char * const USER_FILE_VERSION("ProjectExplorer.Project.Updater.FileVersion");
-const char * const WAS_UPDATED("ProjectExplorer.Project.Updater.DidUpdate");
+const char * const USER_FILE_VERSION = "ProjectExplorer.Project.Updater.FileVersion";
+const char * const USER_FILE_HOSTNAME = "ProjectExplorer.Project.Updater.Hostname";
+const char * const WAS_UPDATED = "ProjectExplorer.Project.Updater.DidUpdate";
const char * const PROJECT_FILE_POSTFIX(".user");
// Version 0 is used in Qt Creator 1.3.x and
if (m_lastVersion < 0 || !project)
return QVariantMap();
- QString fileName(fileNameFor(project->file()->fileName()));
+ QString fileName = fileNameFor(project->file()->fileName());
if (!QFile::exists(fileName))
return QVariantMap();
QVariantMap map(reader.restoreValues());
// Get and verify file version:
- const int fileVersion(map.value(QLatin1String(USER_FILE_VERSION), 0).toInt());
+ const int fileVersion = map.value(QLatin1String(USER_FILE_VERSION), 0).toInt();
if (fileVersion < m_firstVersion || fileVersion > m_lastVersion + 1) {
qWarning() << "File version" << fileVersion << "is not supported.";
return QVariantMap();
}
+ // Verify hostname
+ const QString hostname = map.value(QLatin1String(USER_FILE_HOSTNAME)).toString();
+ if (!hostname.isEmpty() && hostname != QHostInfo::localHostName()) {
+ // Ask the user
+ // TODO tr, casing check
+ QMessageBox msgBox(QMessageBox::Question,
+ QApplication::translate("ProjectExplorer::UserFileAccessor",
+ "Project Settings File from a different Host?"),
+ QApplication::translate("ProjectExplorer::UserFileAccessor",
+ "Qt Creator has found a .user settings file from a host %1. "
+ "The hostname for this computer is %2. \n\n"
+ "The .user settings files contain machine specific settings. "
+ "They should not be copied to a different environment. \n\n"
+ "Still load the settigns file?").arg(hostname, QHostInfo::localHostName()),
+ QMessageBox::Yes | QMessageBox::No,
+ Core::ICore::instance()->mainWindow());
+ msgBox.setDefaultButton(QMessageBox::No);
+ msgBox.setEscapeButton(QMessageBox::No);
+ int result = msgBox.exec();
+ if (result == QMessageBox::No)
+ return QVariantMap();
+ }
+
// Do we need to do a update?
if (fileVersion != m_lastVersion + 1) {
map.insert(QLatin1String(WAS_UPDATED), true);
writer.saveValue(i.key(), i.value());
writer.saveValue(QLatin1String(USER_FILE_VERSION), m_lastVersion + 1);
+ writer.saveValue(QLatin1String(USER_FILE_HOSTNAME), QHostInfo::localHostName());
return writer.save(fileNameFor(project->file()->fileName()), "QtCreatorProject");
}
-<plugin name="QmlDesigner" version="2.0.80" compatVersion="2.0.80" experimental="true">
+<plugin name="QmlDesigner" version="2.1.80" compatVersion="2.1.80" experimental="true">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Visual Designer for QML files.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="QmlJSEditor" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="QmlJSEditor" version="2.1.80"/>
</dependencyList>
</plugin>
{
invisibleRootItem()->setFlags(Qt::ItemIsDropEnabled);
- #ifdef _LOCK_ITEMS_
+# ifdef _LOCK_ITEMS_
setColumnCount(3);
- #else
+# else
setColumnCount(2);
- #endif
+# endif
setSupportedDragActions(Qt::LinkAction);
idItem->setEditable(true);
idItem->setData(hash, Qt::UserRole);
- #ifdef _LOCK_ITEMS_
+# ifdef _LOCK_ITEMS_
QStandardItem *lockItem = new QStandardItem;
lockItem->setDragEnabled(true);
lockItem->setDropEnabled(dropEnabled);
lockItem->setEditable(false);
lockItem->setCheckable(true);
lockItem->setData(hash, Qt::UserRole);
- #endif
+# endif
QStandardItem *visibilityItem = new QStandardItem;
visibilityItem->setDropEnabled(dropEnabled);
visibilityItem->setCheckable(false);
}
- #ifdef _LOCK_ITEMS_
+# ifdef _LOCK_ITEMS_
return ItemRow(idItem, lockItem, visibilityItem);
- #else
+# else
return ItemRow(idItem, visibilityItem);
- #endif
+# endif
}
void NavigatorTreeModel::updateItemRow(const ModelNode &node, ItemRow items)
rowList = itemRow.idItem->parent()->takeRow(itemRow.idItem->row());
}
- foreach (const ModelNode &node, modelNodeChildren(node)) {
- removeSubTree(node);
+ foreach (const ModelNode &childNode, modelNodeChildren(node)) {
+ removeSubTree(childNode);
}
qDeleteAll(rowList);
QGroupBox::paintEvent(event);
if (m_animated) {
QPainter p(this);
- p.setOpacity(m_alpha);
- if (!m_pixmap.isNull() && !m_firstExpand)
+ if (!m_pixmap.isNull() && !m_firstExpand) {
+ p.setOpacity(m_alpha);
p.drawPixmap(5, 5, m_pixmap.width(), m_pixmap.height(), m_pixmap);
+ }
}
}
connect(m_editorValue, SIGNAL(modelNodeChanged()), this, SLOT(update()));
}
-PropertyEditorNodeWrapper::PropertyEditorNodeWrapper(QObject *parent) : QObject(parent)
+PropertyEditorNodeWrapper::PropertyEditorNodeWrapper(QObject *parent) : QObject(parent), m_editorValue(NULL)
{
}
m_attachedToModel(false), m_settingSilentState(false)
{
Q_ASSERT(m_editorModel);
+ // base state
+ m_thumbnailsToUpdate.append(false);
}
void StatesEditorView::setCurrentStateSilent(int index)
setCurrentState(0);
+ m_thumbnailsToUpdate.removeAt(index);
m_modelStates.removeAll(state);
state.destroy();
+
m_editorModel->removeState(index);
int newIndex = (index < m_modelStates.count()) ? index : m_modelStates.count() - 1;
return;
m_modelStates.insert(0, baseState());
+ m_thumbnailsToUpdate.insert(0, false);
m_attachedToModel = true;
m_editorModel->insertState(0, baseState().name());
void StatesEditorView::nodeInstancePropertyChanged(const ModelNode &node, const QString &propertyName)
{
if (!m_settingSilentState) {
- if (QmlModelState(node).isValid()) {
- startUpdateTimer(modelStateIndex(node) + 1, 0);
- } else { //a change to the base state update all
- for (int i = 0; i < m_modelStates.count(); ++i)
- startUpdateTimer(i, 0);
- }
+ QmlModelState state = QmlModelState(node);
+ if (state.isValid())
+ {
+ if (m_modelStates.contains(state))
+ m_thumbnailsToUpdate[m_modelStates.indexOf(state)] = true;
+ } else //a change to the base state update all
+ m_thumbnailsToUpdate[0] = true;
+
}
QmlModelView::nodeInstancePropertyChanged(node, propertyName);
if (debug)
qDebug() << __FUNCTION__;
+ if (identifier == "__end rewriter transaction__")
+ {
+ if (m_thumbnailsToUpdate[0])
+ {
+ for (int i = 0; i < m_modelStates.count(); ++i) {
+ m_thumbnailsToUpdate[i] = false;
+ startUpdateTimer(i, 0);
+ }
+ } else
+ for (int i = 1; i< m_thumbnailsToUpdate.count(); i++)
+ if (m_thumbnailsToUpdate[i]) {
+ m_thumbnailsToUpdate[i] = false;
+ startUpdateTimer(i,0);
+ }
+ }
+
QmlModelView::customNotification(view, identifier, nodeList, data);
}
// For m_modelStates / m_editorModel, i=0 is base state
m_modelStates.insert(i+1, state);
m_editorModel->insertState(i+1, state.name());
+ m_thumbnailsToUpdate.append(false);
}
void StatesEditorView::removeModelState(const QmlModelState &state)
int index = m_modelStates.indexOf(state);
if (index != -1) {
m_modelStates.removeOne(state);
+ m_thumbnailsToUpdate.removeAt(index);
if (m_updateTimerIdList.contains(index)) {
killTimer(m_updateTimerIdList[index]);
const int modelStateCount = m_modelStates.size();
for (int i=modelStateCount-1; i>=0; --i) {
m_modelStates.removeAt(i);
+ m_thumbnailsToUpdate.removeAt(i);
m_editorModel->removeState(i);
}
}
QmlModelState m_oldRewriterAmendState;
bool m_attachedToModel;
bool m_settingSilentState;
+
+ QList<bool> m_thumbnailsToUpdate;
};
} // namespace Internal
ModelNode resolveToModelNode() const;
AbstractProperty resolveToProperty() const;
+ bool isList() const;
+ QList<ModelNode> resolveToModelNodeList() const;
protected:
BindingProperty(const QString &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view);
QString scopeAndName(const QString &combiner = QString("::")) const;
QList<QString> elementNames() const;
int elementValue(const QString &enumeratorName) const;
+ QString valueToString(int value) const;
private:
void setScope(const QString &scope);
bool isAncestorOf(const QmlObjectNode &objectNode) const;
+ static QVariant instanceValue(const ModelNode &modelNode, const QString &name);
+
protected:
NodeInstance nodeInstance() const;
QmlObjectNode nodeForInstance(const NodeInstance &instance) const;
class QmlModelView;
class QmlModelStateGroup;
+class QmlObjectNode;
class CORESHARED_EXPORT QmlModelState : public QmlModelNodeFacade
{
void removePropertyChanges(const ModelNode &node);
bool affectsModelNode(const ModelNode &node) const;
+ QList<QmlObjectNode> allAffectedNodes() const;
QString name() const;
void setName(const QString &name);
bool isValid() const;
return m_data->elements.value(unscoped, -1);
}
+QString EnumeratorMetaInfo::valueToString(int value) const
+{
+ return m_data->elements.key(value);
+}
+
void EnumeratorMetaInfo::setScope(const QString &scope)
{
Q_ASSERT(!scope.isEmpty());
<element name="NonModal" value="0" />
<element name="ApplicationModal" value="2" />
</enumerator>
+ <enumerator name="Type" scope="QEasingCurve">
+ <element name="Linear" value="0" />
+ <element name="InQuad" value="1" />
+ <element name="OutQuad" value="2" />
+ <element name="InOutQuad" value="3" />
+ <element name="OutInQuad" value="4" />
+ <element name="InCubic" value="5" />
+ <element name="OutCubic" value="6" />
+ <element name="InOutCubic" value="7" />
+ <element name="OutInCubic" value="8" />
+ <element name="InQuart" value="9" />
+ <element name="OutQuart" value="10" />
+ <element name="InOutQuart" value="11" />
+ <element name="OutInQuart" value="12" />
+ <element name="InQuint" value="13" />
+ <element name="OutQuint" value="14" />
+ <element name="InOutQuint" value="15" />
+ <element name="OutInQuint" value="16" />
+ <element name="InSine" value="17" />
+ <element name="OutSine" value="18" />
+ <element name="InOutSine" value="19" />
+ <element name="OutInSine" value="20" />
+ <element name="InExpo" value="21" />
+ <element name="OutExpo" value="22" />
+ <element name="InOutExpo" value="23" />
+ <element name="OutInExpo" value="24" />
+ <element name="InCirc" value="25" />
+ <element name="OutCirc" value="26" />
+ <element name="InOutCirc" value="27" />
+ <element name="OutInCirc" value="28" />
+ <element name="InElastic" value="29" />
+ <element name="OutElastic" value="30" />
+ <element name="InOutElastic" value="31" />
+ <element name="OutInElastic" value="32" />
+ <element name="InBack" value="33" />
+ <element name="OutBack" value="34" />
+ <element name="InOutBack" value="35" />
+ <element name="OutInBack" value="36" />
+ <element name="InBounce" value="37" />
+ <element name="OutBounce" value="38" />
+ <element name="InOutBounce" value="39" />
+ <element name="OutInBounce" value="40" />
+ <element name="InCurve" value="41" />
+ <element name="OutCurve" value="42" />
+ <element name="SineCurve" value="43" />
+ <element name="CosineCurve" value="44" />
+ <element name="Custom" value="45" />
+ <element name="NCurveTypes" value="46" />
+ </enumerator>
<flag name="Alignment" scope="Qt">
<element name="AlignLeft" value="1" />
<element name="AlignTrailing" value="2" />
loadPlugins(&engine);
parseQmlTypes();
parseNonQmlTypes();
- parseValueTypes();
parseXmlFiles();
+ parseValueTypes();
m_isInitialized = true;
}
propertyInfo.setFlagType(qProperty.isFlagType());
if (propertyInfo.isEnumType()) {
- EnumeratorMetaInfo enumerator;
-
QMetaEnum qEnumerator = qProperty.enumerator();
+ EnumeratorMetaInfo enumerator = m_q->addEnumerator(qEnumerator.scope(), qEnumerator.name());
+
enumerator.setValid(qEnumerator.isValid());
enumerator.setIsFlagType(qEnumerator.isFlag());
enumerator.setScope(qEnumerator.scope());
}
propertyInfo.setEnumerator(enumerator);
+
}
nodeMetaInfo.addProperty(propertyInfo);
<< "QRectF"
<< "QSize"
<< "QSizeF"
- << "QVector3D";
+ << "QVector3D"
+ << "QEasingCurve";
foreach (const QString &type, valueTypes) {
NodeMetaInfo nodeMetaInfo(*m_q);
propertyInfo.setType("int");
} else if (type == ("QRect")) {
propertyInfo.setType("int");
+ } else if (type == ("QEasingCurve")) {
+ if (propertyName == "type") {
+ propertyInfo.setEnumType("true");
+ propertyInfo.setType("QEasingCurve::Type");
+ propertyInfo.setEnumerator(m_q->enumerator("QEasingCurve::Type"));
+ }
}
propertyInfo.setValid(true);
propertyInfo.setReadable(true);
*/
PropertyMetaInfo AbstractProperty::metaInfo() const
{
- return ModelNode(m_internalNode, m_model.data(), view()).metaInfo().property(m_propertyName);
+ return ModelNode(m_internalNode, m_model.data(), view()).metaInfo().property(m_propertyName, true);
}
/*!
#include <extensionsystem/pluginmanager.h>
#include <qmljs/qmljsdocument.h>
-#include <qmljseditor/qmljsmodelmanagerinterface.h>
+#include <qmljs/qmljsmodelmanagerinterface.h>
#include <texteditor/tabsettings.h>
using namespace QmlDesigner;
-using namespace QmlJSEditor;
BaseTextEditModifier::BaseTextEditModifier(TextEditor::BaseTextEditor *textEdit):
PlainTextEditModifier(textEdit)
}
namespace {
-static inline QmlJSEditor::ModelManagerInterface *getModelManager()
+static inline QmlJS::ModelManagerInterface *getModelManager()
{
ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance();
- return pluginManager->getObject<QmlJSEditor::ModelManagerInterface>();
+ return pluginManager->getObject<QmlJS::ModelManagerInterface>();
}
}
QmlJS::Snapshot BaseTextEditModifier::getSnapshot() const
{
- QmlJSEditor::ModelManagerInterface *modelManager = getModelManager();
+ QmlJS::ModelManagerInterface *modelManager = getModelManager();
if (modelManager)
return modelManager->snapshot();
else
QStringList BaseTextEditModifier::importPaths() const
{
- QmlJSEditor::ModelManagerInterface *modelManager = getModelManager();
+ QmlJS::ModelManagerInterface *modelManager = getModelManager();
if (modelManager)
return modelManager->importPaths();
else
return resolveBinding(expression(), parentModelNode(), view());
}
+static inline QStringList commaSeparatedSimplifiedStringList(const QString &string)
+{
+ QStringList stringList = string.split(QLatin1String(","));
+ QStringList simpleList;
+ foreach (const QString &simpleString, stringList)
+ simpleList.append(simpleString.simplified());
+ return simpleList;
+}
+
+
AbstractProperty BindingProperty::resolveToProperty() const
{
if (!isValid())
return AbstractProperty();
}
+bool BindingProperty::isList() const
+{
+ if (!isValid())
+ throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
+
+ return expression().startsWith('[') && expression().endsWith(']');
+}
+
+QList<ModelNode> BindingProperty::resolveToModelNodeList() const
+{
+ QList<ModelNode> returnList;
+ if (!isValid())
+ throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
+ if (isList()) {
+ QString string = expression();
+ string.chop(1);
+ string.remove(0, 1);
+ QStringList simplifiedList = commaSeparatedSimplifiedStringList(string);
+ foreach (const QString &nodeId, simplifiedList) {
+ ModelNode modelNode = view()->modelNodeForId(nodeId);
+ if (modelNode.isValid())
+ returnList.append(modelNode);
+ }
+ }
+ return returnList;
+}
+
void BindingProperty::setDynamicTypeNameAndExpression(const QString &typeName, const QString &expression)
{
*/
InternalNode::InternalNode() :
- m_valid(false)
+ m_valid(false),
+ m_majorVersion(0),
+ m_minorVersion(0)
{
}
**
**************************************************************************/
- #ifndef PROPERTYPARSER_H
+#ifndef PROPERTYPARSER_H
#define PROPERTYPARSER_H
#include <QtCore/QVariant>
*/
QVariant QmlObjectNode::instanceValue(const QString &name) const
-{
- Q_ASSERT(qmlModelView()->hasInstanceForModelNode(modelNode()));
- return qmlModelView()->instanceForModelNode(modelNode()).property(name);
+{
+ return instanceValue(modelNode(), name);
}
return modelNode().isAncestorOf(objectNode.modelNode());
}
+QVariant QmlObjectNode::instanceValue(const ModelNode &modelNode, const QString &name)
+{
+ QmlModelView *modelView = qobject_cast<QmlModelView*>(modelNode.view());
+ if (!modelView)
+ throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
+ Q_ASSERT(modelView->hasInstanceForModelNode(modelNode));
+ return modelView->instanceForModelNode(modelNode).property(name);
+}
+
NodeInstance QmlObjectNode::nodeInstance() const
{
return qmlModelView()->nodeInstanceView()->instanceForNode(modelNode());
{
//### exception if not valid
+ if (!isValid())
+ throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
+
if (isBaseState())
return;
return !stateOperations(node).isEmpty();
}
+QList<QmlObjectNode> QmlModelState::allAffectedNodes() const
+{
+ QList<QmlObjectNode> returnList;
+
+ foreach (const ModelNode &childNode, modelNode().nodeListProperty("changes").toModelNodeList()) {
+ //### exception if not valid QmlModelStateOperation
+ if (QmlModelStateOperation(childNode).isValid() &&
+ !returnList.contains(QmlModelStateOperation(childNode).target()))
+ returnList.append(QmlModelStateOperation(childNode).target());
+ }
+ return returnList;
+}
+
QString QmlModelState::name() const
{
if (isBaseState())
clearErrors();
if (inErrorState()) {
+ const QString content = textModifierContent();
qDebug() << "RewriterView::applyChanges() got called while in error state. Will do a quick-exit now.";
- throw RewritingException(__LINE__, __FUNCTION__, __FILE__, "RewriterView::applyChanges() already in error state", textModifierContent());
+ qDebug() << "Content:" << content;
+ throw RewritingException(__LINE__, __FUNCTION__, __FILE__, "RewriterView::applyChanges() already in error state", content);
}
try {
enterErrorState(errors().first().description());
}
} catch (Exception &e) {
+ const QString content = textModifierContent();
+ qDebug() << "RewriterException:" << m_rewritingErrorMessage;
+ qDebug() << "Content:" << content;
enterErrorState(e.description());
}
if (inErrorState()) {
- throw RewritingException(__LINE__, __FUNCTION__, __FILE__, m_rewritingErrorMessage, textModifierContent());
+ const QString content = textModifierContent();
+ qDebug() << "RewriterException:" << m_rewritingErrorMessage;
+ qDebug() << "Content:" << content;
+ throw RewritingException(__LINE__, __FUNCTION__, __FILE__, m_rewritingErrorMessage, content);
}
}
const Interpreter::QmlObjectValue * qmlValue = dynamic_cast<const Interpreter::QmlObjectValue *>(value);
if (qmlValue) {
typeName = qmlValue->packageName() + QLatin1String("/") + qmlValue->className();
- majorVersion = qmlValue->majorVersion();
- minorVersion = qmlValue->minorVersion();
+ majorVersion = qmlValue->version().major();
+ minorVersion = qmlValue->version().minor();
} else if (value) {
for (UiQualifiedId *iter = astTypeNode; iter; iter = iter->next)
if (!iter->next && iter->name)
typeName = iter->name->asString();
- majorVersion = Interpreter::QmlObjectValue::NoVersion;
- minorVersion = Interpreter::QmlObjectValue::NoVersion;
+ majorVersion = ComponentVersion::NoVersion;
+ minorVersion = ComponentVersion::NoVersion;
}
}
#include <QSize>
#include <QSizeF>
#include <QVector3D>
+#include <QEasingCurve>
#include <QMetaProperty>
namespace QmlDesigner {
return VariantParser(QVariant(QRectF()));
if (type == "QVector3D")
return VariantParser(QVariant(QVector3D()));
+ if (type == "QEasingCurve")
+ return VariantParser(QVariant(QEasingCurve()));
return VariantParser(QVariant());
}
if (type == "QRectF")
m_valueType = QDeclarativeValueTypeFactory::valueType(QVariant::RectF);
if (type == "QVector3D")
- m_valueType = QDeclarativeValueTypeFactory::valueType(QVariant::Vector3D);
+ m_valueType = QDeclarativeValueTypeFactory::valueType(QVariant::Vector3D);
+ if (type == "QEasingCurve")
+ m_valueType = QDeclarativeValueTypeFactory::valueType(QVariant::EasingCurve);
}
bool VariantParser::isValid()
tokenList.append(QLatin1String("EmptyPropertiesRemoved"));
return tokenList.join(" ");
-
- return QString();
}
static QString indent(const QString &name = QString()) {
using namespace QmlDesigner;
DesignerSettings::DesignerSettings()
- : openDesignMode(QmlDesigner::Constants::QML_OPENDESIGNMODE_DEFAULT)
+ : openDesignMode(QmlDesigner::Constants::QML_OPENDESIGNMODE_DEFAULT),
+ itemSpacing(0),
+ snapMargin(0)
{}
+
void DesignerSettings::fromSettings(QSettings *settings)
{
settings->beginGroup(QLatin1String(QmlDesigner::Constants::QML_SETTINGS_GROUP));
include(../../../../qtcreator.pri)
-include(../../private_headers.pri)
+include(../../../private_headers.pri)
include(fxplugin.pri)
include(plugindestdir.pri)
TARGET = QmlDesigner
include(../../qtcreatorplugin.pri)
-include(../private_headers.pri)
+include(../../private_headers.pri)
include(qmldesigner_dependencies.pri)
include(../qmljseditor/qmljseditor.pri)
-<plugin name="QmlInspector" version="2.0.80" compatVersion="2.0.80">
+<plugin name="QmlInspector" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Debugger for QML files</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="QmlProjectManager" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
- <dependency name="CppTools" version="2.0.80"/>
- <dependency name="CppEditor" version="2.0.80"/>
- <dependency name="Debugger" version="2.0.80"/>
- <dependency name="QmlJSEditor" version="2.0.80"/>
+ <dependency name="QmlProjectManager" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
+ <dependency name="CppTools" version="2.1.80"/>
+ <dependency name="CppEditor" version="2.1.80"/>
+ <dependency name="Debugger" version="2.1.80"/>
+ <dependency name="QmlJSEditor" version="2.1.80"/>
</dependencyList>
</plugin>
}
const QVector<QTextCharFormat> formats = fs.toTextCharFormats(categories);
- m_highlighter->setFormats(formats.constBegin(), formats.constEnd());
+ m_highlighter->setFormats(formats);
m_highlighter->rehighlight();
m_textEdit->setFont(fs.font());
if (m_mode == SeparateEntryMode)
// *************************************************************************
// PropertiesViewItem
// *************************************************************************
-PropertiesViewItem::PropertiesViewItem(QTreeWidget *widget, Type type)
- : QTreeWidgetItem(widget), type(type)
+PropertiesViewItem::PropertiesViewItem(QTreeWidget *widget, int type)
+ : QTreeWidgetItem(widget, type), m_disabled(false)
{
+
}
-PropertiesViewItem::PropertiesViewItem(QTreeWidgetItem *parent, Type type)
- : QTreeWidgetItem(parent), type(type)
+PropertiesViewItem::PropertiesViewItem(QTreeWidgetItem *parent, int type)
+ : QTreeWidgetItem(parent, type), m_disabled(false)
{
}
QVariant PropertiesViewItem::data (int column, int role) const
{
- if (column == 1) {
- if (role == Qt::ForegroundRole) {
- bool canEdit = data(0, CanEditRole).toBool();
- return canEdit ? qApp->palette().color(QPalette::Foreground) : qApp->palette().color(QPalette::Disabled, QPalette::Foreground);
- }
+ if (role == Qt::ForegroundRole) {
+ bool makeDisabledColor = m_disabled;
+ if (column == 1 && !data(0, CanEditRole).toBool())
+ makeDisabledColor = true;
+ return makeDisabledColor ? qApp->palette().color(QPalette::Disabled, QPalette::Foreground) : qApp->palette().color(QPalette::Foreground);
}
+
return QTreeWidgetItem::data(column, role);
}
{
return data(0, ObjectIdStringRole).toString();
}
+void PropertiesViewItem::setWatchingDisabled(bool disabled)
+{
+ m_disabled = disabled;
+}
+bool PropertiesViewItem::isWatchingDisabled() const
+{
+ return m_disabled;
+}
} // Internal
} // Qml
{
public:
enum Type {
- BindingType,
- OtherType,
- ClassType,
+ BindingType = QTreeWidgetItem::UserType,
+ OtherType = QTreeWidgetItem::UserType + 1,
+ ClassType = QTreeWidgetItem::UserType + 2
};
enum DataRoles {
- CanEditRole = Qt::UserRole + 1,
- ObjectIdStringRole = Qt::UserRole + 50,
- ClassDepthRole = Qt::UserRole + 51
+ CanEditRole = Qt::UserRole,
+ ObjectIdStringRole = Qt::UserRole + 1,
+ ClassDepthRole = Qt::UserRole + 2
};
- PropertiesViewItem(QTreeWidget *widget, Type type = OtherType);
- PropertiesViewItem(QTreeWidgetItem *parent, Type type = OtherType);
+ PropertiesViewItem(QTreeWidget *widget, int type = OtherType);
+ PropertiesViewItem(QTreeWidgetItem *parent, int type = OtherType);
QVariant data (int column, int role) const;
void setData (int column, int role, const QVariant & value);
-
+ void setWatchingDisabled(bool disabled);
+ bool isWatchingDisabled() const;
QDeclarativeDebugPropertyReference property;
- Type type;
+
private:
QString objectIdString() const;
+ bool m_disabled;
};
#include "propertytypefinder.h"
#include <extensionsystem/pluginmanager.h>
-#include <qmljseditor/qmljsmodelmanagerinterface.h>
+#include <qmljs/qmljsmodelmanagerinterface.h>
#include <qmljs/qmljsdocument.h>
#include <QtGui/QApplication>
setObject(obj);
}
-void ObjectPropertiesView::setPropertyValue(PropertiesViewItem *item, const QVariant &value, bool makeGray)
+void ObjectPropertiesView::setPropertyValue(PropertiesViewItem *item, const QVariant &value, bool isDisabled)
{
+ item->setWatchingDisabled(isDisabled);
+
if (value.type() == QVariant::List || value.type() == QVariant::StringList) {
PropertiesViewItem *bindingItem = static_cast<PropertiesViewItem*>(item->takeChild(item->childCount() - 1));
- if (bindingItem && bindingItem->type != PropertiesViewItem::BindingType) {
+ if (bindingItem && bindingItem->type() != PropertiesViewItem::BindingType) {
delete bindingItem;
bindingItem = 0;
}
PropertiesViewItem *child;
for (int i=0; i<variants.count(); ++i) {
child = new PropertiesViewItem(item);
- setPropertyValue(child, variants[i], makeGray);
+ setPropertyValue(child, variants[i], isDisabled);
}
if (bindingItem)
item->setExpanded(true);
}
- if (makeGray) {
- for (int i=0; i<m_tree->columnCount(); ++i)
- item->setForeground(i, Qt::gray);
- }
}
QString ObjectPropertiesView::propertyBaseClass(const QDeclarativeDebugObjectReference &object, const QDeclarativeDebugPropertyReference &property, int &depth)
{
ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance();
- QmlJSEditor::ModelManagerInterface *modelManager = pluginManager->getObject<QmlJSEditor::ModelManagerInterface>();
+ QmlJS::ModelManagerInterface *modelManager = pluginManager->getObject<QmlJS::ModelManagerInterface>();
QmlJS::Snapshot snapshot = modelManager->snapshot();
QmlJS::Document::Ptr document = snapshot.document(object.source().url().path());
{
m_clickedItem = m_tree->itemAt(QPoint(event->pos().x(),
event->pos().y() - m_tree->header()->height()));
+
if (!m_clickedItem)
return;
PropertiesViewItem *propItem = static_cast<PropertiesViewItem *>(m_clickedItem);
+ bool isWatchableItem = propItem->type() != PropertiesViewItem::ClassType &&
+ propItem->type() != PropertiesViewItem::BindingType;
+
QMenu menu;
- if (!isWatched(m_clickedItem)) {
- m_addWatchAction->setText(tr("Watch expression '%1'").arg(propItem->property.name()));
- menu.addAction(m_addWatchAction);
- } else {
- menu.addAction(m_removeWatchAction);
+ if (isWatchableItem) {
+ if (!isWatched(m_clickedItem)) {
+ m_addWatchAction->setText(tr("Watch expression '%1'").arg(propItem->property.name()));
+ m_addWatchAction->setDisabled(propItem->isWatchingDisabled());
+ menu.addAction(m_addWatchAction);
+ } else {
+ menu.addAction(m_removeWatchAction);
+ m_addWatchAction->setDisabled(propItem->isWatchingDisabled());
+ }
}
menu.addSeparator();
+
if (m_showUnwatchableProperties)
m_toggleUnwatchablePropertiesAction->setText(tr("Hide unwatchable properties"));
else
void setObject(const QDeclarativeDebugObjectReference &object);
bool isWatched(QTreeWidgetItem *item);
void setWatched(const QString &property, bool watched);
- void setPropertyValue(PropertiesViewItem *item, const QVariant &value, bool makeGray);
+ void setPropertyValue(PropertiesViewItem *item, const QVariant &value, bool isDisabled);
QDeclarativeEngineDebug *m_client;
QDeclarativeDebugObjectQuery *m_query;
#include "components/expressionquerywidget.h"
#include "components/objectpropertiesview.h"
-#include <debugger/debuggerrunner.h>
+#include <debugger/debuggermanager.h>
#include <debugger/debuggermainwindow.h>
+#include <debugger/debuggerrunner.h>
#include <debugger/debuggeruiswitcher.h>
#include <debugger/debuggerconstants.h>
ProjectExplorer::Environment customEnv = ProjectExplorer::Environment::systemEnvironment(); // empty env by default
customEnv.set(QmlProjectManager::Constants::E_QML_DEBUG_SERVER_PORT, QString::number(m_settings.externalPort()));
- Debugger::Internal::DebuggerRunControl *debuggableRunControl = createDebuggerRunControl(runConfig,
- dlg.qmlViewerPath(), dlg.qmlViewerArguments());
+ Debugger::DebuggerRunControl *debuggableRunControl =
+ createDebuggerRunControl(runConfig, dlg.qmlViewerPath(), dlg.qmlViewerArguments());
return executeDebuggerRunControl(debuggableRunControl, &customEnv);
}
ProjectExplorer::Environment customEnv = runConfig->environment();
customEnv.set(QmlProjectManager::Constants::E_QML_DEBUG_SERVER_PORT, QString::number(m_settings.externalPort()));
- Debugger::Internal::DebuggerRunControl *debuggableRunControl = createDebuggerRunControl(runConfig);
+ Debugger::DebuggerRunControl *debuggableRunControl = createDebuggerRunControl(runConfig);
return executeDebuggerRunControl(debuggableRunControl, &customEnv);
}
-QString QmlInspector::executeDebuggerRunControl(Debugger::Internal::DebuggerRunControl *debuggableRunControl, ProjectExplorer::Environment *environment)
+QString QmlInspector::executeDebuggerRunControl(Debugger::DebuggerRunControl *debuggableRunControl, ProjectExplorer::Environment *environment)
{
ProjectExplorer::ProjectExplorerPlugin *pex = ProjectExplorer::ProjectExplorerPlugin::instance();
return QString(tr("A valid run control was not registered in Qt Creator for this project run configuration."));;
}
-Debugger::Internal::DebuggerRunControl *QmlInspector::createDebuggerRunControl(ProjectExplorer::RunConfiguration *runConfig,
- const QString &executableFile, const QString &executableArguments)
+Debugger::DebuggerRunControl *QmlInspector::createDebuggerRunControl(ProjectExplorer::RunConfiguration *runConfig,
+ const QString &executableFile, const QString &executableArguments)
{
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
- const QList<Debugger::Internal::DebuggerRunControlFactory *> factories = pm->getObjects<Debugger::Internal::DebuggerRunControlFactory>();
+ const QList<Debugger::DebuggerRunControlFactory *> factories = pm->getObjects<Debugger::DebuggerRunControlFactory>();
ProjectExplorer::RunControl *runControl = 0;
- if (m_debugMode == QmlProjectWithCppPlugins) {
-
- const Debugger::DebuggerStartParametersPtr sp(new Debugger::DebuggerStartParameters);
- sp->startMode = Debugger::StartExternal;
- sp->executable = executableFile;
- sp->processArgs = executableArguments.split(QLatin1Char(' '));
+ if (m_debugMode == QmlProjectWithCppPlugins) {
+ Debugger::DebuggerStartParameters sp;
+ sp.startMode = Debugger::StartExternal;
+ sp.executable = executableFile;
+ sp.processArgs = executableArguments.split(QLatin1Char(' '));
runControl = factories.first()->create(sp);
- return qobject_cast<Debugger::Internal::DebuggerRunControl *>(runControl);
+ return qobject_cast<Debugger::DebuggerRunControl *>(runControl);
+ }
- } else if (m_debugMode == CppProjectWithQmlEngines) {
+ if (m_debugMode == CppProjectWithQmlEngines) {
if (factories.length() && factories.first()->canRun(runConfig, ProjectExplorer::Constants::DEBUGMODE)) {
runControl = factories.first()->create(runConfig, ProjectExplorer::Constants::DEBUGMODE);
- return qobject_cast<Debugger::Internal::DebuggerRunControl *>(runControl);
+ return qobject_cast<Debugger::DebuggerRunControl *>(runControl);
}
}
namespace Core {
class IContext;
}
+
namespace Debugger {
-namespace Internal {
class DebuggerRunControl;
-} // Internal
-} // Debugger
+}
namespace Qml {
private:
void updateMenuActions();
- Debugger::Internal::DebuggerRunControl *createDebuggerRunControl(ProjectExplorer::RunConfiguration *runConfig,
- const QString &executableFile = QString(),
- const QString &executableArguments = QString());
- QString executeDebuggerRunControl(Debugger::Internal::DebuggerRunControl *debuggableRunControl, ProjectExplorer::Environment *environment);
+ Debugger::DebuggerRunControl *createDebuggerRunControl(ProjectExplorer::RunConfiguration *runConfig,
+ const QString &executableFile = QString(),
+ const QString &executableArguments = QString());
+ QString executeDebuggerRunControl(Debugger::DebuggerRunControl *debuggableRunControl, ProjectExplorer::Environment *environment);
QString attachToQmlViewerAsExternalApp(ProjectExplorer::Project *project);
QString attachToExternalCppAppWithQml(ProjectExplorer::Project *project);
INCLUDEPATH += .
DEPENDPATH += .
-include(../private_headers.pri)
+include(../../private_headers.pri)
include(components/qmldebugger.pri)
DEFINES += QMLINSPECTOR_LIBRARY
<mime-type type="application/javascript">
<alias type="application/x-javascript"/>
<alias type="text/javascript"/>
+ <alias type="text/x-javascript"/>
<sub-class-of type="text/plain"/>
<comment>Qt Script file</comment>
<glob pattern="*.js"/>
-<plugin name="QmlJSEditor" version="2.0.80" compatVersion="2.0.80">
+<plugin name="QmlJSEditor" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Editor for QML and JavaScript.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
</dependencyList>
</plugin>
#include "qmljscodecompletion.h"
#include "qmlexpressionundercursor.h"
#include "qmljseditor.h"
-#include "qmljsmodelmanagerinterface.h"
+#include <qmljs/qmljsmodelmanagerinterface.h>
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/qmljsbind.h>
#include <qmljs/qmljsinterpreter.h>
namespace {
+enum CompletionRelevance {
+ EnumValueRelevance = -5,
+ SnippetRelevance = -10,
+ PropertyRelevance = -15,
+ SymbolRelevance = -20,
+ KeywordRelevance = -25,
+ TypeRelevance = -30
+};
+
// Temporary workaround until we have proper icons for QML completion items
QIcon iconForColor(const QColor &color)
{
: TextEditor::ICompletionCollector(parent),
m_modelManager(modelManager),
m_editor(0),
- m_startPosition(0)
+ m_startPosition(0),
+ m_restartCompletion(false)
{
Q_ASSERT(modelManager);
}
{ return m_startPosition; }
bool CodeCompletion::shouldRestartCompletion()
-{ return false; }
+{ return m_restartCompletion; }
bool CodeCompletion::supportsEditor(TextEditor::ITextEditable *editor)
{
}
void CodeCompletion::addCompletions(const QHash<QString, const Interpreter::Value *> &newCompletions,
- const QIcon &icon)
+ const QIcon &icon, int relevance)
{
QHashIterator<QString, const Interpreter::Value *> it(newCompletions);
while (it.hasNext()) {
TextEditor::CompletionItem item(this);
item.text = it.key();
item.icon = icon;
+ item.relevance = relevance;
m_completions.append(item);
}
}
void CodeCompletion::addCompletions(const QStringList &newCompletions,
- const QIcon &icon)
+ const QIcon &icon, int relevance)
{
foreach (const QString &text, newCompletions) {
TextEditor::CompletionItem item(this);
item.text = text;
item.icon = icon;
+ item.relevance = relevance;
+ m_completions.append(item);
+ }
+}
+
+void CodeCompletion::addCompletionsPropertyLhs(
+ const QHash<QString, const Interpreter::Value *> &newCompletions,
+ const QIcon &icon, int relevance)
+{
+ QHashIterator<QString, const Interpreter::Value *> it(newCompletions);
+ while (it.hasNext()) {
+ it.next();
+
+ TextEditor::CompletionItem item(this);
+ item.text = it.key();
+ if (const Interpreter::QmlObjectValue *qmlValue = dynamic_cast<const Interpreter::QmlObjectValue *>(it.value())) {
+ // to distinguish "anchors." from "gradient:" we check if the right hand side
+ // type is instantiatable or is the prototype of an instantiatable object
+ if (qmlValue->hasChildInPackage())
+ item.text.append(QLatin1String(": "));
+ else
+ item.text.append(QLatin1Char('.'));
+ } else {
+ item.text.append(QLatin1String(": "));
+ }
+ item.icon = icon;
+ item.relevance = relevance;
m_completions.append(item);
}
}
int CodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
{
+ m_restartCompletion = false;
+
m_editor = editor;
QmlJSTextEditor *edit = qobject_cast<QmlJSTextEditor *>(m_editor->widget());
if (m_startPosition > 0)
completionOperator = editor->characterAt(m_startPosition - 1);
+ QTextCursor startPositionCursor(edit->document());
+ startPositionCursor.setPosition(m_startPosition);
+ CompletionContextFinder contextFinder(startPositionCursor);
+
+ const Interpreter::ObjectValue *qmlScopeType = 0;
+ if (contextFinder.isInQmlContext())
+ qmlScopeType = context.lookupType(document.data(), contextFinder.qmlObjectTypeName());
+
if (completionOperator.isSpace() || completionOperator.isNull() || isDelimiter(completionOperator) ||
(completionOperator == QLatin1Char('(') && m_startPosition != editor->position())) {
bool doQmlKeywordCompletion = true;
bool doJsKeywordCompletion = true;
- QTextCursor startPositionCursor(edit->document());
- startPositionCursor.setPosition(m_startPosition);
- CompletionContextFinder contextFinder(startPositionCursor);
-
- const Interpreter::ObjectValue *qmlScopeType = 0;
- if (contextFinder.isInQmlContext())
- qmlScopeType = context.lookupType(document.data(), contextFinder.qmlObjectTypeName());
-
if (contextFinder.isInLhsOfBinding() && qmlScopeType) {
doGlobalCompletion = false;
doJsKeywordCompletion = false;
enumerateProperties.setGlobalCompletion(true);
enumerateProperties.setEnumerateGeneratedSlots(true);
- addCompletions(enumerateProperties(qmlScopeType), symbolIcon);
- addCompletions(enumerateProperties(context.scopeChain().qmlTypes), symbolIcon);
+ // id: is special
+ TextEditor::CompletionItem idPropertyCompletion(this);
+ idPropertyCompletion.text = QLatin1String("id: ");
+ idPropertyCompletion.icon = symbolIcon;
+ idPropertyCompletion.relevance = PropertyRelevance;
+ m_completions.append(idPropertyCompletion);
+
+ addCompletionsPropertyLhs(enumerateProperties(qmlScopeType), symbolIcon, PropertyRelevance);
+ addCompletions(enumerateProperties(context.scopeChain().qmlTypes), symbolIcon, TypeRelevance);
if (ScopeBuilder::isPropertyChangesObject(&context, qmlScopeType)
&& context.scopeChain().qmlScopeObjects.size() == 2) {
- addCompletions(enumerateProperties(context.scopeChain().qmlScopeObjects.first()), symbolIcon);
+ addCompletions(enumerateProperties(context.scopeChain().qmlScopeObjects.first()), symbolIcon, SymbolRelevance);
}
}
item.text = key;
item.data = QString("\"%1\"").arg(key);
item.icon = symbolIcon;
+ item.relevance = EnumValueRelevance;
m_completions.append(item);
}
}
// It's a global completion.
EnumerateProperties enumerateProperties(&context);
enumerateProperties.setGlobalCompletion(true);
- addCompletions(enumerateProperties(), symbolIcon);
+ addCompletions(enumerateProperties(), symbolIcon, SymbolRelevance);
}
if (doJsKeywordCompletion) {
// add js keywords
- addCompletions(Scanner::keywords(), keywordIcon);
+ addCompletions(Scanner::keywords(), keywordIcon, KeywordRelevance);
}
// add qml extra words
<< QLatin1String("function");
}
- addCompletions(qmlWords, keywordIcon);
+ addCompletions(qmlWords, keywordIcon, KeywordRelevance);
if (!doJsKeywordCompletion)
- addCompletions(qmlWordsAlsoInJs, keywordIcon);
+ addCompletions(qmlWordsAlsoInJs, keywordIcon, KeywordRelevance);
}
}
if (value && completionOperator == QLatin1Char('.')) { // member completion
EnumerateProperties enumerateProperties(&context);
- addCompletions(enumerateProperties(value), symbolIcon);
+ if (contextFinder.isInLhsOfBinding() && qmlScopeType && expressionUnderCursor.text().at(0).isLower())
+ addCompletionsPropertyLhs(enumerateProperties(value), symbolIcon, PropertyRelevance);
+ else
+ addCompletions(enumerateProperties(value), symbolIcon, SymbolRelevance);
} else if (value && completionOperator == QLatin1Char('(') && m_startPosition == editor->position()) {
// function completion
if (const Interpreter::FunctionValue *f = value->asFunctionValue()) {
}
}
- const int length = m_editor->position() - m_startPosition;
+ QString replacableChars;
+ if (toInsert.endsWith(QLatin1String(": ")))
+ replacableChars = QLatin1String(": ");
+ else if (toInsert.endsWith(QLatin1String(".")))
+ replacableChars = QLatin1String(".");
+
+ int replacedLength = 0;
+
+ // Avoid inserting characters that are already there
+ for (int i = 0; i < replacableChars.length(); ++i) {
+ const QChar a = replacableChars.at(i);
+ const QChar b = m_editor->characterAt(m_editor->position() + i);
+ if (a == b)
+ ++replacedLength;
+ else
+ break;
+ }
+
+ const int length = m_editor->position() - m_startPosition + replacedLength;
m_editor->setCurPos(m_startPosition);
m_editor->replace(length, toInsert);
+
+ if (toInsert.endsWith(QLatin1Char('.')))
+ m_restartCompletion = true;
}
bool CodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems)
item.details = infotip;
item.icon = icon;
+ item.relevance = SnippetRelevance;
m_snippets.append(item);
break;
}
static bool qmlCompletionItemLessThan(const TextEditor::CompletionItem &l, const TextEditor::CompletionItem &r)
{
- if (l.text.isEmpty())
+ if (l.relevance != r.relevance)
+ return l.relevance > r.relevance;
+ else if (l.text.isEmpty())
return true;
else if (r.text.isEmpty())
return false;
}
namespace QmlJS {
+ class ModelManagerInterface;
+
namespace Interpreter {
class Value;
}
namespace QmlJSEditor {
-class ModelManagerInterface;
-
namespace Internal {
class FunctionArgumentWidget;
Q_OBJECT
public:
- CodeCompletion(ModelManagerInterface *modelManager, QObject *parent = 0);
+ CodeCompletion(QmlJS::ModelManagerInterface *modelManager, QObject *parent = 0);
virtual ~CodeCompletion();
virtual TextEditor::ITextEditable *editor() const;
bool isDelimiter(QChar ch) const;
void addCompletions(const QHash<QString, const QmlJS::Interpreter::Value *> &newCompletions,
- const QIcon &icon);
+ const QIcon &icon, int relevance);
void addCompletions(const QStringList &newCompletions,
- const QIcon &icon);
+ const QIcon &icon, int relevance);
+ void addCompletionsPropertyLhs(
+ const QHash<QString, const QmlJS::Interpreter::Value *> &newCompletions,
+ const QIcon &icon, int relevance);
- ModelManagerInterface *m_modelManager;
+ QmlJS::ModelManagerInterface *m_modelManager;
TextEditor::ITextEditable *m_editor;
int m_startPosition;
QList<TextEditor::CompletionItem> m_completions;
QList<TextEditor::CompletionItem> m_snippets;
QDateTime m_snippetFileLastModified;
QPointer<FunctionArgumentWidget> m_functionArgumentWidget;
+ bool m_restartCompletion;
};
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "qmljscomponentfromobjectdef.h"
+#include "qmljsrefactoringchanges.h"
+
+#include <coreplugin/ifile.h>
+
+#include <qmljs/parser/qmljsast_p.h>
+#include <qmljs/qmljsdocument.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+
+using namespace QmlJS::AST;
+using namespace QmlJSEditor::Internal;
+
+ComponentFromObjectDef::ComponentFromObjectDef(TextEditor::BaseTextEditor *editor)
+ : QmlJSQuickFixOperation(editor), _objDef(0)
+{}
+
+static QString getId(UiObjectDefinition *def)
+{
+ if (def && def->initializer) {
+ for (UiObjectMemberList *iter = def->initializer->members; iter; iter = iter->next) {
+ if (UiScriptBinding *script = cast<UiScriptBinding*>(iter->member)) {
+ if (!script->qualifiedId)
+ continue;
+ if (script->qualifiedId->next)
+ continue;
+ if (script->qualifiedId->name) {
+ if (script->qualifiedId->name->asString() == QLatin1String("id")) {
+ ExpressionStatement *expStmt = cast<ExpressionStatement *>(script->statement);
+ if (!expStmt)
+ continue;
+ if (IdentifierExpression *idExp = cast<IdentifierExpression *>(expStmt->expression)) {
+ return idExp->name->asString();
+ } else if (StringLiteral *strExp = cast<StringLiteral *>(expStmt->expression)) {
+ return strExp->value->asString();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return QString();
+}
+
+QString ComponentFromObjectDef::description() const
+{
+ return QCoreApplication::translate("QmlJSEditor::ComponentFromObjectDef",
+ "Extract Component");
+}
+
+void ComponentFromObjectDef::createChanges()
+{
+ Q_ASSERT(_objDef != 0);
+
+ QString componentName = getId(_objDef);
+ componentName[0] = componentName.at(0).toUpper();
+
+ const QString path = editor()->file()->fileName();
+ const QString newFileName = QFileInfo(path).path() + QDir::separator() + componentName + QLatin1String(".qml");
+
+ QString imports;
+ UiProgram *prog = semanticInfo().document->qmlProgram();
+ if (prog && prog->imports) {
+ const int start = startPosition(prog->imports->firstSourceLocation());
+ const int end = startPosition(prog->members->member->firstSourceLocation());
+ imports = textOf(start, end);
+ }
+
+ const int start = startPosition(_objDef->firstSourceLocation());
+ const int end = startPosition(_objDef->lastSourceLocation());
+ const QString txt = imports + textOf(start, end) + QLatin1String("}\n");
+
+ Utils::ChangeSet changes;
+ changes.replace(start, end - start, componentName + QLatin1String(" {\n"));
+ qmljsRefactoringChanges()->changeFile(fileName(), changes);
+ qmljsRefactoringChanges()->reindent(fileName(), range(start, end + 1));
+
+ qmljsRefactoringChanges()->createFile(newFileName, txt);
+ qmljsRefactoringChanges()->reindent(newFileName, range(0, txt.length() - 1));
+}
+
+int ComponentFromObjectDef::check()
+{
+ _objDef = 0;
+ const int pos = textCursor().position();
+
+ QList<Node *> path = semanticInfo().astPath(pos);
+ for (int i = path.size() - 1; i >= 0; --i) {
+ Node *node = path.at(i);
+ if (UiObjectDefinition *objDef = cast<UiObjectDefinition *>(node)) {
+ if (i > 0 && !cast<UiProgram*>(path.at(i - 1))) { // node is not the root node
+ if (!getId(objDef).isEmpty()) {
+ _objDef = objDef;
+ return 0;
+ }
+ }
+ }
+ }
+
+ return -1;
+}
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
-#ifndef TOKENUNDERCURSOR_H
-#define TOKENUNDERCURSOR_H
-#include "SimpleLexer.h"
-#include <QList>
+#ifndef QMLJSCOMPONENTFROMOBJECTDEF_H
+#define QMLJSCOMPONENTFROMOBJECTDEF_H
-QT_BEGIN_NAMESPACE
-class QString;
-class QTextCursor;
-class QTextBlock;
-QT_END_NAMESPACE
+#include "qmljsquickfix.h"
-namespace CPlusPlus {
+namespace QmlJSEditor {
+namespace Internal {
-class CPLUSPLUS_EXPORT TokenUnderCursor
+class ComponentFromObjectDef: public QmlJSQuickFixOperation
{
public:
- TokenUnderCursor();
- ~TokenUnderCursor();
+ ComponentFromObjectDef(TextEditor::BaseTextEditor *editor);
- SimpleToken operator()(const QTextCursor &cursor, QTextBlock *block = 0);
-
- const QList<SimpleToken> &tokens() const
- { return _tokens; }
+ virtual QString description() const;
+ virtual void createChanges();
+ virtual int check();
private:
- QList<SimpleToken> _tokens;
- QString _text;
+ QmlJS::AST::UiObjectDefinition *_objDef;
};
-} // end of namespace CPlusPlus
+} // namespace Internal
+} // namespace QmlJSEditor
-#endif // TOKENUNDERCURSOR_H
+#endif // QMLJSCOMPONENTFROMOBJECTDEF_H
range.ast = member;
range.begin = QTextCursor(_textDocument);
- range.begin.setPosition(ast->lbraceToken.begin());
+ range.begin.setPosition(member->firstSourceLocation().begin());
range.end = QTextCursor(_textDocument);
range.end.setPosition(ast->rbraceToken.end());
return document()->revision();
}
+bool QmlJSTextEditor::isOutdated() const
+{
+ if (m_semanticInfo.revision() != documentRevision())
+ return true;
+
+ return false;
+}
+
Core::IEditor *QmlJSEditorEditable::duplicate(QWidget *parent)
{
QmlJSTextEditor *newEditor = new QmlJSTextEditor(parent);
<< QLatin1String(TextEditor::Constants::C_VISUAL_WHITESPACE);
}
- const QVector<QTextCharFormat> formats = fs.toTextCharFormats(categories);
- highlighter->setFormats(formats.constBegin(), formats.constEnd());
+ highlighter->setFormats(fs.toTextCharFormats(categories));
highlighter->rehighlight();
m_occurrencesFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_OCCURRENCES));
return semanticInfo;
}
-void SemanticHighlighter::setModelManager(QmlJSEditor::ModelManagerInterface *modelManager)
+void SemanticHighlighter::setModelManager(QmlJS::ModelManagerInterface *modelManager)
{
m_modelManager = modelManager;
}
class ICore;
}
-namespace QmlJSEditor {
+namespace QmlJS {
+ class ModelManagerInterface;
+}
-class ModelManagerInterface;
+namespace QmlJSEditor {
class Highlighter;
namespace Internal {
};
void rehighlight(const Source &source);
- void setModelManager(ModelManagerInterface *modelManager);
+ void setModelManager(QmlJS::ModelManagerInterface *modelManager);
Q_SIGNALS:
void changed(const QmlJSEditor::Internal::SemanticInfo &semanticInfo);
bool m_done;
Source m_source;
SemanticInfo m_lastSemanticInfo;
- ModelManagerInterface *m_modelManager;
+ QmlJS::ModelManagerInterface *m_modelManager;
};
class QmlJSTextEditor : public TextEditor::BaseTextEditor
SemanticInfo semanticInfo() const;
int documentRevision() const;
+ bool isOutdated() const;
public slots:
void followSymbolUnderCursor();
QTimer *m_updateUsesTimer;
QTimer *m_semanticRehighlightTimer;
QComboBox *m_methodCombo;
- ModelManagerInterface *m_modelManager;
+ QmlJS::ModelManagerInterface *m_modelManager;
QTextCharFormat m_occurrencesFormat;
QTextCharFormat m_occurrencesUnusedFormat;
QTextCharFormat m_occurrenceRenameFormat;
qmljshighlighter.h \
qmljshoverhandler.h \
qmljsmodelmanager.h \
- qmljsmodelmanagerinterface.h \
- qmljspreviewrunner.h
+ qmljspreviewrunner.h \
+ qmljsquickfix.h \
+ qmljsrefactoringchanges.h \
+ qmljscomponentfromobjectdef.h
SOURCES += \
qmljscodecompletion.cpp \
qmljshighlighter.cpp \
qmljshoverhandler.cpp \
qmljsmodelmanager.cpp \
- qmljsmodelmanagerinterface.cpp \
- qmljspreviewrunner.cpp
+ qmljspreviewrunner.cpp \
+ qmljsquickfix.cpp \
+ qmljsrefactoringchanges.cpp \
+ qmljscomponentfromobjectdef.cpp
RESOURCES += qmljseditor.qrc
OTHER_FILES += QmlJSEditor.pluginspec QmlJSEditor.mimetypes.xml
#include "qmljsmodelmanager.h"
#include "qmlfilewizard.h"
#include "qmljspreviewrunner.h"
+#include "qmljsquickfix.h"
#include <qmldesigner/qmldesignerconstants.h>
#include <QtCore/QSettings>
#include <QtCore/QDir>
#include <QtCore/QCoreApplication>
+#include <QtCore/QTimer>
#include <QtGui/QMenu>
#include <QtGui/QAction>
using namespace QmlJSEditor::Internal;
using namespace QmlJSEditor::Constants;
+enum {
+ QUICKFIX_INTERVAL = 20
+};
+
QmlJSEditorPlugin *QmlJSEditorPlugin::m_instance = 0;
QmlJSEditorPlugin::QmlJSEditorPlugin() :
m_actionHandler(0)
{
m_instance = this;
+
+ m_quickFixCollector = 0;
+ m_quickFixTimer = new QTimer(this);
+ m_quickFixTimer->setInterval(20);
+ m_quickFixTimer->setSingleShot(true);
+ connect(m_quickFixTimer, SIGNAL(timeout()), this, SLOT(quickFixNow()));
}
QmlJSEditorPlugin::~QmlJSEditorPlugin()
Core::FileIconProvider *iconProvider = Core::FileIconProvider::instance();
iconProvider->registerIconOverlayForSuffix(QIcon(":/qmljseditor/images/qmlfile.png"), "qml");
+ m_quickFixCollector = new QmlJSQuickFixCollector;
+ addAutoReleasedObject(m_quickFixCollector);
+
return true;
}
// auto completion
connect(editor, SIGNAL(requestAutoCompletion(TextEditor::ITextEditable*, bool)),
TextEditor::Internal::CompletionSupport::instance(), SLOT(autoComplete(TextEditor::ITextEditable*, bool)));
+
+ // quick fix
+ connect(editor, SIGNAL(requestQuickFix(TextEditor::ITextEditable*)),
+ this, SLOT(quickFix(TextEditor::ITextEditable*)));
}
void QmlJSEditorPlugin::followSymbolUnderCursor()
return command;
}
+QmlJSQuickFixCollector *QmlJSEditorPlugin::quickFixCollector() const
+{ return m_quickFixCollector; }
+
+void QmlJSEditorPlugin::quickFix(TextEditor::ITextEditable *editable)
+{
+ m_currentTextEditable = editable;
+ quickFixNow();
+}
+
+void QmlJSEditorPlugin::quickFixNow()
+{
+ if (! m_currentTextEditable)
+ return;
+
+ Core::EditorManager *em = Core::EditorManager::instance();
+ QmlJSTextEditor *currentEditor = qobject_cast<QmlJSTextEditor*>(em->currentEditor()->widget());
+
+ if (QmlJSTextEditor *editor = qobject_cast<QmlJSTextEditor*>(m_currentTextEditable->widget())) {
+ if (currentEditor == editor) {
+ if (editor->isOutdated()) {
+ // qDebug() << "TODO: outdated document" << editor->documentRevision() << editor->semanticInfo().revision();
+ // ### FIXME: m_quickFixTimer->start(QUICKFIX_INTERVAL);
+ m_quickFixTimer->stop();
+ } else {
+ TextEditor::Internal::CompletionSupport::instance()->quickFix(m_currentTextEditable);
+ }
+ }
+ }
+}
Q_EXPORT_PLUGIN(QmlJSEditorPlugin)
#define QMLJSEDITORPLUGIN_H
#include <extensionsystem/iplugin.h>
+#include <QtCore/QPointer>
QT_FORWARD_DECLARE_CLASS(QAction)
+QT_FORWARD_DECLARE_CLASS(QTimer)
namespace TextEditor {
class TextEditorActionHandler;
class ActionManager;
}
+namespace TextEditor {
+class ITextEditable;
+}
+
+namespace QmlJS {
+ class ModelManagerInterface;
+}
+
namespace QmlJSEditor {
-class ModelManagerInterface;
class QmlFileWizard;
namespace Internal {
class QmlJSEditorFactory;
class QmlJSTextEditor;
class QmlJSPreviewRunner;
+class QmlJSQuickFixCollector;
class QmlJSEditorPlugin : public ExtensionSystem::IPlugin
{
static QmlJSEditorPlugin *instance()
{ return m_instance; }
+ QmlJSQuickFixCollector *quickFixCollector() const;
+
void initializeEditor(QmlJSTextEditor *editor);
public Q_SLOTS:
private Q_SLOTS:
void openPreview();
+ void quickFix(TextEditor::ITextEditable *editable);
+ void quickFixNow();
private:
Core::Command *addToolAction(QAction *a, Core::ActionManager *am, const QList<int> &context, const QString &name,
QAction *m_actionPreview;
QmlJSPreviewRunner *m_previewRunner;
- ModelManagerInterface *m_modelManager;
+ QmlJS::ModelManagerInterface *m_modelManager;
QmlFileWizard *m_wizard;
QmlJSEditorFactory *m_editor;
TextEditor::TextEditorActionHandler *m_actionHandler;
+
+ QmlJSQuickFixCollector *m_quickFixCollector;
+
+ QTimer *m_quickFixTimer;
+ QPointer<TextEditor::ITextEditable> m_currentTextEditable;
};
} // namespace Internal
Highlighter::Highlighter(QTextDocument *parent)
: QSyntaxHighlighter(parent),
- m_qmlEnabled(true)
+ m_qmlEnabled(true),
+ m_inMultilineComment(false)
{
m_currentBlockParentheses.reserve(20);
m_braceDepth = 0;
+ m_foldingIndent = 0;
}
Highlighter::~Highlighter()
} // end of switch
}
+void Highlighter::setFormats(const QVector<QTextCharFormat> &formats)
+{
+ QTC_ASSERT(formats.size() == NumFormats, return);
+ qCopy(formats.begin(), formats.end(), m_formats);
+}
+
void Highlighter::highlightBlock(const QString &text)
{
const QList<Token> tokens = m_scanner(text, onBlockStart());
break;
case Token::Comment:
+ if (m_inMultilineComment && text.midRef(token.end() - 2, 2) == QLatin1String("*/")) {
+ onClosingParenthesis('-', token.end() - 1, index == tokens.size()-1);
+ m_inMultilineComment = false;
+ } else if (!m_inMultilineComment
+ && m_scanner.state() == Scanner::MultiLineComment
+ && index == tokens.size() - 1) {
+ onOpeningParenthesis('+', token.offset, index == 0);
+ m_inMultilineComment = true;
+ }
setFormat(token.offset, token.length, m_formats[CommentFormat]);
break;
case Token::LeftParenthesis:
- onOpeningParenthesis('(', token.offset);
+ onOpeningParenthesis('(', token.offset, index == 0);
break;
case Token::RightParenthesis:
- onClosingParenthesis(')', token.offset);
+ onClosingParenthesis(')', token.offset, index == tokens.size()-1);
break;
case Token::LeftBrace:
- onOpeningParenthesis('{', token.offset);
+ onOpeningParenthesis('{', token.offset, index == 0);
break;
case Token::RightBrace:
- onClosingParenthesis('}', token.offset);
+ onClosingParenthesis('}', token.offset, index == tokens.size()-1);
break;
case Token::LeftBracket:
- onOpeningParenthesis('[', token.offset);
+ onOpeningParenthesis('[', token.offset, index == 0);
break;
case Token::RightBracket:
- onClosingParenthesis(']', token.offset);
+ onClosingParenthesis(']', token.offset, index == tokens.size()-1);
break;
case Token::Identifier: {
setFormat(previousTokenEnd, text.length() - previousTokenEnd, m_formats[VisualWhitespace]);
- int firstNonSpace = 0;
- if (! tokens.isEmpty())
- firstNonSpace = tokens.first().offset;
-
setCurrentBlockState(m_scanner.state());
- onBlockEnd(m_scanner.state(), firstNonSpace);
+ onBlockEnd(m_scanner.state());
}
bool Highlighter::maybeQmlKeyword(const QStringRef &text) const
{
m_currentBlockParentheses.clear();
m_braceDepth = 0;
+ m_foldingIndent = 0;
+ m_inMultilineComment = false;
+ if (TextEditor::TextBlockUserData *userData = TextEditor::BaseTextDocumentLayout::testUserData(currentBlock())) {
+ userData->setFoldingIndent(0);
+ userData->setFoldingStartIncluded(false);
+ userData->setFoldingEndIncluded(false);
+ }
int state = 0;
int previousState = previousBlockState();
if (previousState != -1) {
state = previousState & 0xff;
- m_braceDepth = previousState >> 8;
+ m_inMultilineComment = (previousState >> 8) & 0xff;
+ m_braceDepth = previousState >> 16;
}
+ m_foldingIndent = m_braceDepth;
return state;
}
-void Highlighter::onBlockEnd(int state, int firstNonSpace)
+void Highlighter::onBlockEnd(int state)
{
typedef TextEditor::TextBlockUserData TextEditorBlockData;
- setCurrentBlockState((m_braceDepth << 8) | state);
-
- // Set block data parentheses. Force creation of block data unless empty
- TextEditorBlockData *blockData = 0;
-
- if (QTextBlockUserData *userData = currentBlockUserData())
- blockData = static_cast<TextEditorBlockData *>(userData);
-
- if (!blockData && !m_currentBlockParentheses.empty()) {
- blockData = new TextEditorBlockData;
- setCurrentBlockUserData(blockData);
- }
- if (blockData) {
- blockData->setParentheses(m_currentBlockParentheses);
- blockData->setClosingCollapseMode(TextEditor::TextBlockUserData::NoClosingCollapse);
- blockData->setCollapseMode(TextEditor::TextBlockUserData::NoCollapse);
- }
- if (!m_currentBlockParentheses.isEmpty()) {
- QTC_ASSERT(blockData, return);
- int collapse = Parenthesis::collapseAtPos(m_currentBlockParentheses);
- if (collapse >= 0) {
- if (collapse == firstNonSpace)
- blockData->setCollapseMode(TextEditor::TextBlockUserData::CollapseThis);
- else
- blockData->setCollapseMode(TextEditor::TextBlockUserData::CollapseAfter);
- }
- if (Parenthesis::hasClosingCollapse(m_currentBlockParentheses))
- blockData->setClosingCollapseMode(TextEditor::TextBlockUserData::NoClosingCollapse);
- }
+ setCurrentBlockState((m_braceDepth << 16) | (m_inMultilineComment << 8) | state);
+ TextEditor::BaseTextDocumentLayout::setParentheses(currentBlock(), m_currentBlockParentheses);
+ TextEditor::BaseTextDocumentLayout::setFoldingIndent(currentBlock(), m_foldingIndent);
}
-void Highlighter::onOpeningParenthesis(QChar parenthesis, int pos)
+void Highlighter::onOpeningParenthesis(QChar parenthesis, int pos, bool atStart)
{
- if (parenthesis == QLatin1Char('{') || parenthesis == QLatin1Char('['))
+ if (parenthesis == QLatin1Char('{') || parenthesis == QLatin1Char('[') || parenthesis == QLatin1Char('+')) {
++m_braceDepth;
+ // if a folding block opens at the beginning of a line, treat the entire line
+ // as if it were inside the folding block
+ if (atStart)
+ TextEditor::BaseTextDocumentLayout::userData(currentBlock())->setFoldingStartIncluded(true);
+ }
m_currentBlockParentheses.push_back(Parenthesis(Parenthesis::Opened, parenthesis, pos));
}
-void Highlighter::onClosingParenthesis(QChar parenthesis, int pos)
+void Highlighter::onClosingParenthesis(QChar parenthesis, int pos, bool atEnd)
{
- if (parenthesis == QLatin1Char('}') || parenthesis == QLatin1Char(']'))
+ if (parenthesis == QLatin1Char('}') || parenthesis == QLatin1Char(']') || parenthesis == QLatin1Char('-')) {
--m_braceDepth;
+ if (atEnd)
+ TextEditor::BaseTextDocumentLayout::userData(currentBlock())->setFoldingEndIncluded(true);
+ else
+ m_foldingIndent = qMin(m_braceDepth, m_foldingIndent); // folding indent is the minimum brace depth of a block
+ }
m_currentBlockParentheses.push_back(Parenthesis(Parenthesis::Closed, parenthesis, pos));
}
bool isQmlEnabled() const;
void setQmlEnabled(bool duiEnabled);
-
- // MS VC 6 compatible, still.
- // Set formats from a sequence of type QTextCharFormat
- template <class InputIterator>
- void setFormats(InputIterator begin, InputIterator end)
- {
- qCopy(begin, end, m_formats);
- }
+ void setFormats(const QVector<QTextCharFormat> &formats);
QTextCharFormat labelTextCharFormat() const;
virtual void highlightBlock(const QString &text);
int onBlockStart();
- void onBlockEnd(int state, int firstNonSpace);
+ void onBlockEnd(int state);
// The functions are notified whenever parentheses are encountered.
// Custom behaviour can be added, for example storing info for indenting.
- void onOpeningParenthesis(QChar parenthesis, int pos);
- void onClosingParenthesis(QChar parenthesis, int pos);
+ void onOpeningParenthesis(QChar parenthesis, int pos, bool atStart);
+ void onClosingParenthesis(QChar parenthesis, int pos, bool atEnd);
bool maybeQmlKeyword(const QStringRef &text) const;
bool maybeQmlBuiltinType(const QStringRef &text) const;
bool m_qmlEnabled;
int m_braceDepth;
+ int m_foldingIndent;
+ bool m_inMultilineComment;
QmlJS::Scanner m_scanner;
Parentheses m_currentBlockParentheses;
HoverHandler::HoverHandler(QObject *parent)
: QObject(parent)
{
- m_modelManager = ExtensionSystem::PluginManager::instance()->getObject<ModelManagerInterface>();
+ m_modelManager = ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>();
// Listen for editor opened events in order to connect to tooltip/helpid requests
connect(ICore::instance()->editorManager(), SIGNAL(editorOpened(Core::IEditor *)),
#ifndef QMLJSHOVERHANDLER_H
#define QMLJSHOVERHANDLER_H
-#include "qmljsmodelmanagerinterface.h"
-
+#include <qmljs/qmljsmodelmanagerinterface.h>
#include <QtCore/QObject>
QT_BEGIN_NAMESPACE
QStringList *baseClasses) const;
private:
- ModelManagerInterface *m_modelManager;
+ QmlJS::ModelManagerInterface *m_modelManager;
QString m_helpId;
QString m_toolTip;
};
#include <QtConcurrentRun>
#include <qtconcurrent/runextensions.h>
#include <QTextStream>
+#include <QCoreApplication>
#include <QDebug>
QDir::Files,
QDir::Name);
- const QStringList errors = Interpreter::MetaTypeSystem::load(xmlFiles);
+ const QStringList errors = Interpreter::CppQmlTypesLoader::load(xmlFiles);
foreach (const QString &error, errors)
qWarning() << qPrintable(error);
+
+ // loads the builtin types
+ loadQmlPluginTypes(QString());
}
Snapshot ModelManager::snapshot() const
{
QMutexLocker locker(&m_mutex);
+ if (!_snapshot.libraryInfo(path).isValid())
+ loadQmlPluginTypes(path);
+
_snapshot.insertLibraryInfo(path, info);
}
QStringList *importedFiles, QSet<QString> *scannedPaths)
{
// scan files and directories that are explicitly imported
- foreach (const QString &fileImport, doc->bind()->fileImports()) {
- if (! snapshot.document(fileImport))
- *importedFiles += fileImport;
+ foreach (const Bind::ImportInfo &fileImport, doc->bind()->fileImports()) {
+ if (! snapshot.document(fileImport.name))
+ *importedFiles += fileImport.name;
}
- foreach (const QString &directoryImport, doc->bind()->directoryImports()) {
- if (snapshot.documentsInDirectory(directoryImport).isEmpty()) {
- if (! scannedPaths->contains(directoryImport)) {
- *importedFiles += qmlFilesInDirectory(directoryImport);
- scannedPaths->insert(directoryImport);
+ foreach (const Bind::ImportInfo &directoryImport, doc->bind()->directoryImports()) {
+ if (snapshot.documentsInDirectory(directoryImport.name).isEmpty()) {
+ if (! scannedPaths->contains(directoryImport.name)) {
+ *importedFiles += qmlFilesInDirectory(directoryImport.name);
+ scannedPaths->insert(directoryImport.name);
}
}
}
{
// scan library imports
const QStringList importPaths = modelManager->importPaths();
- foreach (const QString &libraryImport, doc->bind()->libraryImports()) {
+ foreach (const Bind::ImportInfo &libraryImport, doc->bind()->libraryImports()) {
foreach (const QString &importPath, importPaths) {
QDir dir(importPath);
- dir.cd(libraryImport);
+ dir.cd(libraryImport.name);
const QString targetPath = dir.absolutePath();
// if we know there is a library, done
return paths;
}
+
+void ModelManager::loadQmlPluginTypes(const QString &pluginPath)
+{
+ static QString qmldumpPath;
+ if (qmldumpPath.isNull()) {
+ QDir qmldumpExecutable(QCoreApplication::applicationDirPath());
+#ifndef Q_OS_WIN
+ qmldumpPath = qmldumpExecutable.absoluteFilePath(QLatin1String("qmldump"));
+#else
+ qmldumpPath = qmldumpExecutable.absoluteFilePath(QLatin1String("qmldump.exe"));
+#endif
+ QFileInfo qmldumpFileInfo(qmldumpPath);
+ if (!qmldumpFileInfo.exists()) {
+ qWarning() << "ModelManager::loadQmlPluginTypes: qmldump executable does not exist at" << qmldumpPath;
+ qmldumpPath.clear();
+ } else if (!qmldumpFileInfo.isFile()) {
+ qWarning() << "ModelManager::loadQmlPluginTypes: " << qmldumpPath << " is not a file";
+ qmldumpPath.clear();
+ }
+
+ }
+ if (qmldumpPath.isEmpty())
+ return;
+
+ QProcess *process = new QProcess(this);
+ connect(process, SIGNAL(finished(int)), SLOT(qmlPluginTypeDumpDone(int)));
+ process->start(qmldumpPath, QStringList(pluginPath));
+ m_runningQmldumps.insert(process, pluginPath);
+}
+
+void ModelManager::qmlPluginTypeDumpDone(int exitCode)
+{
+ QProcess *process = qobject_cast<QProcess *>(sender());
+ if (!process)
+ return;
+ process->deleteLater();
+ if (exitCode != 0)
+ return;
+
+ const QByteArray output = process->readAllStandardOutput();
+ QMap<QString, Interpreter::FakeMetaObject *> newObjects;
+ const QString error = Interpreter::CppQmlTypesLoader::parseQmlTypeXml(output, &newObjects);
+ if (!error.isEmpty())
+ return;
+
+ // convert from QList<T *> to QList<const T *>
+ QList<const Interpreter::FakeMetaObject *> objectsList;
+ QMapIterator<QString, Interpreter::FakeMetaObject *> it(newObjects);
+ while (it.hasNext()) {
+ it.next();
+ objectsList.append(it.value());
+ }
+
+ const QString libraryPath = m_runningQmldumps.take(process);
+
+ QMutexLocker locker(&m_mutex);
+
+ if (!libraryPath.isEmpty()) {
+ LibraryInfo libraryInfo = _snapshot.libraryInfo(libraryPath);
+ libraryInfo.setMetaObjects(objectsList);
+ _snapshot.insertLibraryInfo(libraryPath, libraryInfo);
+ } else {
+ Interpreter::CppQmlTypesLoader::builtinObjects.append(objectsList);
+ }
+}
#ifndef QMLJSMODELMANAGER_H
#define QMLJSMODELMANAGER_H
-#include "qmljsmodelmanagerinterface.h"
-
+#include <qmljs/qmljsmodelmanagerinterface.h>
#include <qmljs/qmljsdocument.h>
#include <QFuture>
#include <QFutureSynchronizer>
#include <QMutex>
+#include <QProcess>
namespace Core {
class ICore;
namespace QmlJSEditor {
namespace Internal {
-class ModelManager: public ModelManagerInterface
+class ModelManager: public QmlJS::ModelManagerInterface
{
Q_OBJECT
// this should be executed in the GUI thread.
void onDocumentUpdated(QmlJS::Document::Ptr doc);
void onLibraryInfoUpdated(const QString &path, const QmlJS::LibraryInfo &info);
+ void qmlPluginTypeDumpDone(int exitCode);
protected:
struct WorkingCopy
bool emitDocChangedOnDisk);
void loadQmlTypeDescriptions();
+ void loadQmlPluginTypes(const QString &pluginPath);
private:
static bool matchesMimeType(const Core::MimeType &fileMimeType, const Core::MimeType &knownMimeType);
QmlJS::Snapshot _snapshot;
QStringList m_projectImportPaths;
QStringList m_defaultImportPaths;
+ QHash<QProcess *, QString> m_runningQmldumps;
QFutureSynchronizer<void> m_synchronizer;
};
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "qmljsquickfix.h"
+#include "qmljscomponentfromobjectdef.h"
+#include "qmljseditor.h"
+#include "qmljsrefactoringchanges.h"
+#include "qmljs/parser/qmljsast_p.h"
+
+#include <extensionsystem/pluginmanager.h>
+
+#include <qmljs/qmljsmodelmanagerinterface.h>
+
+#include <QtGui/QApplication>
+#include <QtCore/QDebug>
+
+using namespace QmlJSEditor;
+using namespace QmlJSEditor::Internal;
+using TextEditor::RefactoringChanges;
+
+class QmlJSQuickFixState: public TextEditor::QuickFixState
+{
+public:
+ SemanticInfo semanticInfo;
+};
+
+namespace {
+
+class SplitInitializerOp: public QmlJSQuickFixOperation {
+public:
+ SplitInitializerOp(TextEditor::BaseTextEditor *editor)
+ : QmlJSQuickFixOperation(editor), _objectInitializer(0)
+ {}
+
+ virtual QString description() const
+ {
+ return QApplication::translate("QmlJSEditor::QuickFix", "Split initializer");
+ }
+
+ virtual void createChanges()
+ {
+ Q_ASSERT(_objectInitializer != 0);
+
+ Utils::ChangeSet changes;
+
+ for (QmlJS::AST::UiObjectMemberList *it = _objectInitializer->members; it; it = it->next) {
+ if (QmlJS::AST::UiObjectMember *member = it->member) {
+ const QmlJS::AST::SourceLocation loc = member->firstSourceLocation();
+
+ // insert a newline at the beginning of this binding
+ changes.insert(startPosition(loc), QLatin1String("\n"));
+ }
+ }
+
+ // insert a newline before the closing brace
+ changes.insert(startPosition(_objectInitializer->rbraceToken),
+ QLatin1String("\n"));
+
+ refactoringChanges()->changeFile(fileName(), changes);
+ refactoringChanges()->reindent(fileName(),
+ range(startPosition(_objectInitializer->lbraceToken),
+ startPosition(_objectInitializer->rbraceToken)));
+
+ }
+
+ virtual int check()
+ {
+ _objectInitializer = 0;
+
+ const int pos = textCursor().position();
+
+ if (QmlJS::AST::Node *member = semanticInfo().declaringMember(pos)) {
+ if (QmlJS::AST::UiObjectBinding *b = QmlJS::AST::cast<QmlJS::AST::UiObjectBinding *>(member)) {
+ if (b->initializer->lbraceToken.startLine == b->initializer->rbraceToken.startLine)
+ _objectInitializer = b->initializer;
+
+ } else if (QmlJS::AST::UiObjectDefinition *b = QmlJS::AST::cast<QmlJS::AST::UiObjectDefinition *>(member)) {
+ if (b->initializer->lbraceToken.startLine == b->initializer->rbraceToken.startLine)
+ _objectInitializer = b->initializer;
+ }
+ }
+
+ if (! _objectInitializer)
+ return -1;
+
+ return 0; // very high priority
+ }
+
+private:
+ QmlJS::AST::UiObjectInitializer *_objectInitializer;
+};
+
+
+} // end of anonymous namespace
+
+
+QmlJSQuickFixOperation::QmlJSQuickFixOperation(TextEditor::BaseTextEditor *editor)
+ : TextEditor::QuickFixOperation(editor)
+ , _refactoringChanges(0)
+{
+}
+
+QmlJSQuickFixOperation::~QmlJSQuickFixOperation()
+{
+ if (_refactoringChanges)
+ delete _refactoringChanges;
+}
+
+QmlJS::Document::Ptr QmlJSQuickFixOperation::document() const
+{
+ return _semanticInfo.document;
+}
+
+const QmlJS::Snapshot &QmlJSQuickFixOperation::snapshot() const
+{
+ return _semanticInfo.snapshot;
+}
+
+const SemanticInfo &QmlJSQuickFixOperation::semanticInfo() const
+{
+ return _semanticInfo;
+}
+
+int QmlJSQuickFixOperation::match(TextEditor::QuickFixState *state)
+{
+ QmlJS::ModelManagerInterface *modelManager = ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>();
+ QmlJSQuickFixState *s = static_cast<QmlJSQuickFixState *>(state);
+ _semanticInfo = s->semanticInfo;
+ if (_refactoringChanges) {
+ delete _refactoringChanges;
+ }
+ _refactoringChanges = new QmlJSRefactoringChanges(modelManager, _semanticInfo.snapshot);
+ return check();
+}
+
+QString QmlJSQuickFixOperation::fileName() const
+{
+ return document()->fileName();
+}
+
+void QmlJSQuickFixOperation::apply()
+{
+ _refactoringChanges->apply();
+}
+
+QmlJSRefactoringChanges *QmlJSQuickFixOperation::qmljsRefactoringChanges() const
+{ return _refactoringChanges; }
+
+RefactoringChanges *QmlJSQuickFixOperation::refactoringChanges() const
+{ return qmljsRefactoringChanges(); }
+
+unsigned QmlJSQuickFixOperation::startPosition(const QmlJS::AST::SourceLocation &loc) const
+{
+ return position(loc.startLine, loc.startColumn);
+}
+
+QmlJSQuickFixCollector::QmlJSQuickFixCollector()
+{
+}
+
+QmlJSQuickFixCollector::~QmlJSQuickFixCollector()
+{
+}
+
+bool QmlJSQuickFixCollector::supportsEditor(TextEditor::ITextEditable *editable)
+{
+ if (qobject_cast<QmlJSTextEditor *>(editable->widget()) != 0)
+ return true;
+
+ return false;
+}
+
+TextEditor::QuickFixState *QmlJSQuickFixCollector::initializeCompletion(TextEditor::ITextEditable *editable)
+{
+ if (QmlJSTextEditor *editor = qobject_cast<QmlJSTextEditor *>(editable->widget())) {
+ const SemanticInfo info = editor->semanticInfo();
+
+ if (editor->isOutdated()) {
+ // outdated
+ qWarning() << "TODO: outdated semantic info, force a reparse.";
+ return 0;
+ }
+
+ QmlJSQuickFixState *state = new QmlJSQuickFixState;
+ state->semanticInfo = info;
+ return state;
+ }
+
+ return 0;
+}
+
+QList<TextEditor::QuickFixOperation::Ptr> QmlJSQuickFixCollector::quickFixOperations(TextEditor::BaseTextEditor *editor) const
+{
+ QList<TextEditor::QuickFixOperation::Ptr> quickFixOperations;
+ quickFixOperations.append(TextEditor::QuickFixOperation::Ptr(new SplitInitializerOp(editor)));
+ quickFixOperations.append(TextEditor::QuickFixOperation::Ptr(new ComponentFromObjectDef(editor)));
+ return quickFixOperations;
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef QMLJSQUICKFIX_H
+#define QMLJSQUICKFIX_H
+
+#include "qmljseditor.h"
+
+#include <texteditor/quickfix.h>
+#include <qmljs/parser/qmljsastfwd_p.h>
+#include <qmljs/qmljsdocument.h>
+
+namespace QmlJS {
+ class ModelManagerInterface;
+}
+
+namespace QmlJSEditor {
+class QmlJSRefactoringChanges;
+
+namespace Internal {
+
+class QmlJSQuickFixOperation: public TextEditor::QuickFixOperation
+{
+ Q_DISABLE_COPY(QmlJSQuickFixOperation)
+
+public:
+ QmlJSQuickFixOperation(TextEditor::BaseTextEditor *editor);
+ virtual ~QmlJSQuickFixOperation();
+
+ QmlJS::Document::Ptr document() const;
+ const QmlJS::Snapshot &snapshot() const;
+ const SemanticInfo &semanticInfo() const;
+
+ virtual int check() = 0;
+ virtual int match(TextEditor::QuickFixState *state);
+
+protected:
+ using TextEditor::QuickFixOperation::textOf;
+ using TextEditor::QuickFixOperation::charAt;
+ using TextEditor::QuickFixOperation::position;
+
+ QString fileName() const;
+
+ virtual void apply();
+ QmlJSRefactoringChanges *qmljsRefactoringChanges() const;
+ virtual TextEditor::RefactoringChanges *refactoringChanges() const;
+
+ unsigned startPosition(const QmlJS::AST::SourceLocation &loc) const;
+
+private:
+ SemanticInfo _semanticInfo;
+ QmlJSRefactoringChanges *_refactoringChanges;
+};
+
+class QmlJSQuickFixCollector: public TextEditor::QuickFixCollector
+{
+ Q_OBJECT
+
+public:
+ QmlJSQuickFixCollector();
+ virtual ~QmlJSQuickFixCollector();
+
+ virtual bool supportsEditor(TextEditor::ITextEditable *editor);
+ virtual TextEditor::QuickFixState *initializeCompletion(TextEditor::ITextEditable *editable);
+ virtual QList<TextEditor::QuickFixOperation::Ptr> quickFixOperations(TextEditor::BaseTextEditor *editor) const;
+};
+
+} // end of namespace Internal
+} // end of namespace QmlJSEditor
+
+#endif // QMLJSQUICKFIX_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "qmljsrefactoringchanges.h"
+
+#include <qmljs/qmljsmodelmanagerinterface.h>
+
+using namespace QmlJS;
+using namespace QmlJSEditor;
+
+QmlJSRefactoringChanges::QmlJSRefactoringChanges(ModelManagerInterface *modelManager,
+ const Snapshot &snapshot)
+ : m_modelManager(modelManager)
+ , m_snapshot(snapshot)
+{
+ Q_ASSERT(modelManager);
+}
+
+QStringList QmlJSRefactoringChanges::apply()
+{
+ const QStringList changedFiles = TextEditor::RefactoringChanges::apply();
+ m_modelManager->updateSourceFiles(changedFiles, true);
+ return changedFiles;
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef QMLREFACTORINGCHANGES_H
+#define QMLREFACTORINGCHANGES_H
+
+#include <qmljs/qmljsdocument.h>
+
+#include <texteditor/refactoringchanges.h>
+
+namespace QmlJS {
+class ModelManagerInterface;
+} // namespace QmlJS
+
+namespace QmlJSEditor {
+
+class QmlJSRefactoringChanges: public TextEditor::RefactoringChanges
+{
+public:
+ QmlJSRefactoringChanges(QmlJS::ModelManagerInterface *modelManager,
+ const QmlJS::Snapshot &snapshot);
+
+ virtual QStringList apply();
+
+private:
+ QmlJS::ModelManagerInterface *m_modelManager;
+ QmlJS::Snapshot m_snapshot;
+};
+
+} // namespace QmlJSEditor
+
+#endif // QMLREFACTORINGCHANGES_H
-<plugin name="QmlProjectManager" version="2.0.80" compatVersion="2.0.80">
+<plugin name="QmlProjectManager" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Qt Quick support</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="ProjectExplorer" version="2.0.80"/>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="QmlJSEditor" version="2.0.80"/>
- <dependency name="Debugger" version="2.0.80" />
+ <dependency name="ProjectExplorer" version="2.1.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="QmlJSEditor" version="2.1.80"/>
+ <dependency name="Debugger" version="2.1.80" />
</dependencyList>
</plugin>
#include <coreplugin/messagemanager.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/filewatcher.h>
-#include <qmljseditor/qmljsmodelmanagerinterface.h>
+#include <qmljs/qmljsmodelmanagerinterface.h>
#include <QTextStream>
#include <QDeclarativeComponent>
QmlProject::QmlProject(Internal::Manager *manager, const QString &fileName)
: m_manager(manager),
m_fileName(fileName),
- m_modelManager(ExtensionSystem::PluginManager::instance()->getObject<QmlJSEditor::ModelManagerInterface>()),
+ m_modelManager(ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>()),
m_fileWatcher(new ProjectExplorer::FileWatcher(this)),
m_targetFactory(new Internal::QmlProjectTargetFactory(this))
{
#include <QtDeclarative/QDeclarativeEngine>
-namespace QmlJSEditor {
+namespace QmlJS {
class ModelManagerInterface;
}
QString m_fileName;
Internal::QmlProjectFile *m_file;
QString m_projectName;
- QmlJSEditor::ModelManagerInterface *m_modelManager;
+ QmlJS::ModelManagerInterface *m_modelManager;
// plain format
QStringList m_files;
return false;
}
+void QmlProjectFile::rename(const QString &newName)
+{
+ // Can't happen...
+ Q_UNUSED(newName);
+ Q_ASSERT(false);
+}
+
QString QmlProjectFile::fileName() const
{
return m_fileName;
virtual bool save(const QString &fileName = QString());
virtual QString fileName() const;
+ virtual void rename(const QString &newName);
virtual QString defaultPath() const;
virtual QString suggestedFileName() const;
namespace QmlProjectManager {
namespace Constants {
-const char * const QML_RC_ID("QmlProjectManager.QmlRunConfiguration");
-const char * const QML_RC_DISPLAY_NAME(QT_TRANSLATE_NOOP("QmlProjectManager::Internal::QmlRunConfiguration", "QML Viewer"));
-const char * const QML_VIEWER_KEY("QmlProjectManager.QmlRunConfiguration.QDeclarativeViewer");
-const char * const QML_VIEWER_ARGUMENTS_KEY("QmlProjectManager.QmlRunConfiguration.QDeclarativeViewerArguments");
-const char * const QML_VIEWER_TARGET_ID("QmlProjectManager.QmlTarget");
-const char * const QML_VIEWER_TARGET_DISPLAY_NAME("QML Viewer");
-const char * const QML_MAINSCRIPT_KEY("QmlProjectManager.QmlRunConfiguration.MainScript");
-const char * const QML_DEBUG_SERVER_ADDRESS_KEY("QmlProjectManager.QmlRunConfiguration.DebugServerAddress");
-const char * const QML_DEBUG_SERVER_PORT_KEY("QmlProjectManager.QmlRunConfiguration.DebugServerPort");
+const char * const QML_RC_ID = "QmlProjectManager.QmlRunConfiguration";
+const char * const QML_RC_DISPLAY_NAME = QT_TRANSLATE_NOOP("QmlProjectManager::Internal::QmlRunConfiguration", "QML Viewer");
+const char * const QML_VIEWER_KEY = "QmlProjectManager.QmlRunConfiguration.QDeclarativeViewer";
+const char * const QML_VIEWER_ARGUMENTS_KEY = "QmlProjectManager.QmlRunConfiguration.QDeclarativeViewerArguments";
+const char * const QML_VIEWER_TARGET_ID = "QmlProjectManager.QmlTarget";
+const char * const QML_VIEWER_TARGET_DISPLAY_NAME = "QML Viewer";
+const char * const QML_MAINSCRIPT_KEY = "QmlProjectManager.QmlRunConfiguration.MainScript";
+const char * const QML_DEBUG_SERVER_ADDRESS_KEY = "QmlProjectManager.QmlRunConfiguration.DebugServerAddress";
+const char * const QML_DEBUG_SERVER_PORT_KEY = "QmlProjectManager.QmlRunConfiguration.DebugServerPort";
-const int QML_DEFAULT_DEBUG_SERVER_PORT(3768);
+const int QML_DEFAULT_DEBUG_SERVER_PORT = 3768;
} // namespace Constants
} // namespace QmlProjectManager
return true;
}
-QList<ProjectExplorer::ProjectNode::ProjectAction> QmlProjectNode::supportedActions() const
+QList<ProjectExplorer::ProjectNode::ProjectAction> QmlProjectNode::supportedActions(Node *node) const
{
+ Q_UNUSED(node);
QList<ProjectAction> actions;
actions.append(AddFile);
return actions;
virtual bool hasBuildTargets() const;
- virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions() const;
+ virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions(Node *node) const;
virtual bool addSubProjects(const QStringList &proFilePaths);
virtual bool removeSubProjects(const QStringList &proFilePaths);
#include <texteditor/texteditoractionhandler.h>
#include <projectexplorer/taskwindow.h>
-#include <qmljseditor/qmljsmodelmanagerinterface.h>
+#include <qmljs/qmljsmodelmanagerinterface.h>
#include <QtCore/QtPlugin>
ProjectExplorer::TaskWindow *taskWindow = pluginManager->getObject<ProjectExplorer::TaskWindow>();
m_qmlTaskManager->setTaskWindow(taskWindow);
- QmlJSEditor::ModelManagerInterface *modelManager = pluginManager->getObject<QmlJSEditor::ModelManagerInterface>();
+ QmlJS::ModelManagerInterface *modelManager = pluginManager->getObject<QmlJS::ModelManagerInterface>();
Q_ASSERT(modelManager);
connect(modelManager, SIGNAL(documentChangedOnDisk(QmlJS::Document::Ptr)),
m_qmlTaskManager, SLOT(documentChangedOnDisk(QmlJS::Document::Ptr)));
{
if (!canCreate(parent, id))
return 0;
- QmlProjectTarget *qmlparent(static_cast<QmlProjectTarget *>(parent));
+ QmlProjectTarget *qmlparent = static_cast<QmlProjectTarget *>(parent);
return new QmlProjectRunConfiguration(qmlparent);
}
bool QmlProjectRunConfigurationFactory::canRestore(ProjectExplorer::Target *parent, const QVariantMap &map) const
{
- QString id(ProjectExplorer::idFromMap(map));
+ QString id = ProjectExplorer::idFromMap(map);
return canCreate(parent, id);
}
{
if (!canRestore(parent, map))
return 0;
- QmlProjectTarget *qmlparent(static_cast<QmlProjectTarget *>(parent));
- QmlProjectRunConfiguration *rc(new QmlProjectRunConfiguration(qmlparent));
+ QmlProjectTarget *qmlparent = static_cast<QmlProjectTarget *>(parent);
+ QmlProjectRunConfiguration *rc = new QmlProjectRunConfiguration(qmlparent);
if (rc->fromMap(map))
return rc;
delete rc;
{
if (!canClone(parent, source))
return 0;
- QmlProjectTarget *qmlparent(static_cast<QmlProjectTarget *>(parent));
+ QmlProjectTarget *qmlparent = static_cast<QmlProjectTarget *>(parent);
return new QmlProjectRunConfiguration(qmlparent, qobject_cast<QmlProjectRunConfiguration *>(source));
}
namespace QmlProjectManager {
namespace Internal {
-QmlRunControl::QmlRunControl(QmlProjectRunConfiguration *runConfiguration, bool debugMode)
- : RunControl(runConfiguration), m_debugMode(debugMode)
+QmlRunControl::QmlRunControl(QmlProjectRunConfiguration *runConfiguration, QString mode)
+ : RunControl(runConfiguration, mode)
{
ProjectExplorer::Environment environment = ProjectExplorer::Environment::systemEnvironment();
- if (debugMode)
+ if (runMode() == ProjectExplorer::Constants::DEBUGMODE)
environment.set(QmlProjectManager::Constants::E_QML_DEBUG_SERVER_PORT, QString::number(runConfiguration->debugServerPort()));
m_applicationLauncher.setEnvironment(environment.toStringList());
void QmlRunControl::slotAddToOutputWindow(const QString &line, bool onStdErr)
{
- if (m_debugMode && line.startsWith("QDeclarativeDebugServer: Waiting for connection")) {
+ if (runMode() == ProjectExplorer::Constants::DEBUGMODE && line.startsWith("QDeclarativeDebugServer: Waiting for connection")) {
Core::ICore *core = Core::ICore::instance();
core->modeManager()->activateMode(Debugger::Constants::MODE_DEBUG);
}
const QString &mode)
{
QTC_ASSERT(canRun(runConfiguration, mode), return 0);
- return new QmlRunControl(qobject_cast<QmlProjectRunConfiguration *>(runConfiguration),
- mode == ProjectExplorer::Constants::DEBUGMODE);
+ return new QmlRunControl(qobject_cast<QmlProjectRunConfiguration *>(runConfiguration), mode);
}
QString QmlRunControlFactory::displayName() const
namespace Internal {
-class QmlRunControl : public ProjectExplorer::RunControl {
+class QmlRunControl : public ProjectExplorer::RunControl
+{
Q_OBJECT
public:
- explicit QmlRunControl(QmlProjectRunConfiguration *runConfiguration, bool debugMode);
+ explicit QmlRunControl(QmlProjectRunConfiguration *runConfiguration, QString mode);
virtual ~QmlRunControl ();
// RunControl
QString m_executable;
QStringList m_commandLineArguments;
- bool m_debugMode;
};
class QmlRunControlFactory : public ProjectExplorer::IRunControlFactory {
-<plugin name="Qt4ProjectManager" version="2.0.80" compatVersion="2.0.80">
+<plugin name="Qt4ProjectManager" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Provides project type for Qt 4 pro files and tools.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
- <dependency name="CppTools" version="2.0.80"/>
- <dependency name="CppEditor" version="2.0.80"/>
- <dependency name="Designer" version="2.0.80"/>
- <dependency name="Debugger" version="2.0.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
+ <dependency name="CppTools" version="2.1.80"/>
+ <dependency name="CppEditor" version="2.1.80"/>
+ <dependency name="Designer" version="2.1.80"/>
+ <dependency name="Debugger" version="2.1.80"/>
</dependencyList>
</plugin>
#include "qt4projectmanagerconstants.h"
#include "profileeditorfactory.h"
+#include <coreplugin/icore.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/uniqueidmanager.h>
#include <texteditor/fontsettings.h>
#include <texteditor/texteditoractionhandler.h>
#include <texteditor/texteditorsettings.h>
#include <QtCore/QFileInfo>
+#include <QtGui/QMenu>
using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal;
ah->setupActions(this);
baseTextDocument()->setSyntaxHighlighter(new ProFileHighlighter);
+ m_commentDefinition.clearCommentStyles();
+ m_commentDefinition.setSingleLine(QString(QLatin1Char('#')));
}
ProFileEditor::~ProFileEditor()
{
}
+void ProFileEditor::unCommentSelection()
+{
+ Utils::unCommentSelection(this, m_commentDefinition);
+}
+
TextEditor::BaseTextEditorEditable *ProFileEditor::createEditableInterface()
{
return new ProFileEditorEditable(this);
}
+void ProFileEditor::contextMenuEvent(QContextMenuEvent *e)
+{
+ QMenu *menu = new QMenu();
+
+ Core::ActionManager *am = Core::ICore::instance()->actionManager();
+ Core::ActionContainer *mcontext = am->actionContainer(Qt4ProjectManager::Constants::M_CONTEXT);
+ QMenu *contextMenu = mcontext->menu();
+
+ foreach (QAction *action, contextMenu->actions())
+ menu->addAction(action);
+
+ appendStandardContextMenuActions(menu);
+
+ menu->exec(e->globalPos());
+ delete menu;
+}
+
void ProFileEditor::setFontSettings(const TextEditor::FontSettings &fs)
{
TextEditor::BaseTextEditor::setFontSettings(fs);
#include <texteditor/basetextdocument.h>
#include <texteditor/basetexteditor.h>
+#include <utils/uncommentselection.h>
namespace TextEditor {
class FontSettings;
ProFileEditorFactory *factory() { return m_factory; }
TextEditor::TextEditorActionHandler *actionHandler() const { return m_ah; }
+
+ void unCommentSelection();
+
protected:
TextEditor::BaseTextEditorEditable *createEditableInterface();
+ void contextMenuEvent(QContextMenuEvent *);
public slots:
virtual void setFontSettings(const TextEditor::FontSettings &);
private:
ProFileEditorFactory *m_factory;
TextEditor::TextEditorActionHandler *m_ah;
+ Utils::CommentDefinition m_commentDefinition;
};
class ProFileDocument : public TextEditor::BaseTextDocument
#include <QtGui/QLabel>
#include <QtGui/QVBoxLayout>
#include <QtGui/QWizardPage>
+#include <QtGui/QApplication>
using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal;
// We used to simply call ::exec() on the dialog
void ProjectLoadWizard::execDialog()
{
- if (!pageIds().isEmpty())
+ if (!pageIds().isEmpty()) {
+ QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
exec();
- else
+ QApplication::restoreOverrideCursor();
+ } else {
done(QDialog::Accepted);
+ }
}
ProjectLoadWizard::~ProjectLoadWizard()
#include <QtCore/QFile>
#include <QtCore/QTextStream>
+using namespace ExtensionSystem;
+using namespace ProjectExplorer;
+
namespace Qt4ProjectManager {
namespace Internal {
Q_ASSERT(!m_instance);
m_instance = this;
+ QemuRuntimeManager::instance(this);
MaemoDeviceConfigurations::instance(this);
- ExtensionSystem::PluginManager *pluginManager
- = ExtensionSystem::PluginManager::instance();
+ PluginManager *pluginManager = PluginManager::instance();
pluginManager->addObject(m_runControlFactory);
pluginManager->addObject(m_runConfigurationFactory);
pluginManager->addObject(m_packageCreationFactory);
MaemoManager::~MaemoManager()
{
- ExtensionSystem::PluginManager *pluginManager
- = ExtensionSystem::PluginManager::instance();
+ PluginManager *pluginManager = PluginManager::instance();
pluginManager->removeObject(m_runControlFactory);
pluginManager->removeObject(m_runConfigurationFactory);
pluginManager->removeObject(m_packageCreationFactory);
return *m_instance;
}
-void MaemoManager::init()
-{
- m_qemuRuntimeManager = new QemuRuntimeManager(this);
-}
-
-bool
-MaemoManager::isValidMaemoQtVersion(const Qt4ProjectManager::QtVersion *version) const
+bool MaemoManager::isValidMaemoQtVersion(const QtVersion *version) const
{
QString path = QDir::cleanPath(version->qmakeCommand());
path = path.remove(QLatin1String("/bin/qmake" EXEC_SUFFIX));
return false;
}
-ProjectExplorer::ToolChain*
-MaemoManager::maemoToolChain(const QtVersion *version) const
+ToolChain* MaemoManager::maemoToolChain(const QtVersion *version) const
{
QString targetRoot = QDir::cleanPath(version->qmakeCommand());
targetRoot.remove(QLatin1String("/bin/qmake" EXEC_SUFFIX));
~MaemoManager();
static MaemoManager &instance();
- void init();
-
bool isValidMaemoQtVersion(const Qt4ProjectManager::QtVersion *version) const;
ToolChain *maemoToolChain(const Qt4ProjectManager::QtVersion *version) const;
#include "maemotoolchain.h"
#include <qt4projectmanager/qt4buildconfiguration.h>
+#include <qt4projectmanager/qt4project.h>
+#include <qt4projectmanager/qt4target.h>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
namespace {
const char * const MODIFIED_KEY
= "Qt4ProjectManager.BuildStep.MaemoPackage.Modified";
- const char * const REMOTE_EXE_KEY
- = "Qt4ProjectManager.BuildStep.MaemoPackage.RemoteExe";
+ const char * const REMOTE_EXE_DIR_KEY
+ = "Qt4ProjectManager.BuildStep.MaemoPackage.RemoteExeDir";
const char * const LOCAL_FILES_KEY
= "Qt4ProjectManager.BuildStep.MaemoPackage.LocalFiles";
- const char * const REMOTE_FILES_KEY
- = "Qt4ProjectManager.BuildStep.MaemoPackage.RemoteFiles";
+ const char * const REMOTE_DIRS_KEY
+ = "Qt4ProjectManager.BuildStep.MaemoPackage.RemoteDirs";
}
namespace Qt4ProjectManager {
Q_ASSERT(row >= 0 && row < rowCount());
return row == 0
? Deployable(m_packageStep->localExecutableFilePath(),
- remoteExecutableFilePath())
+ remoteExecutableDir())
: m_deployables.at(row - 1);
}
if (index.column() == 0 && role == Qt::DisplayRole)
return d.localFilePath;
if (role == Qt::DisplayRole || role == Qt::EditRole)
- return d.remoteFilePath;
+ return d.remoteDir;
return QVariant();
}
|| role != Qt::EditRole)
return false;
- const QString &remoteFilePath = value.toString();
+ const QString &remoteDir = value.toString();
if (index.row() == 0)
- m_remoteExecutableFilePath = remoteFilePath;
+ m_remoteExecutableDir = remoteDir;
else
- m_deployables[index.row() - 1].remoteFilePath = remoteFilePath;
+ m_deployables[index.row() - 1].remoteDir = remoteDir;
m_modified = true;
emit dataChanged(index, index);
return true;
{
if (orientation == Qt::Vertical || role != Qt::DisplayRole)
return QVariant();
- return section == 0 ? tr("Local File Path") : tr("Remote File Path");
+ return section == 0 ? tr("Local File Path") : tr("Remote Directory");
}
QVariantMap MaemoPackageContents::toMap() const
{
QVariantMap map;
map.insert(MODIFIED_KEY, m_modified);
- map.insert(REMOTE_EXE_KEY, m_remoteExecutableFilePath);
+ map.insert(REMOTE_EXE_DIR_KEY, m_remoteExecutableDir);
+
+ QDir dir;
QStringList localFiles;
- QStringList remoteFiles;
+ QStringList remoteDirs;
foreach (const Deployable &p, m_deployables) {
- localFiles << p.localFilePath;
- remoteFiles << p.remoteFilePath;
+ localFiles << dir.fromNativeSeparators(p.localFilePath);
+ remoteDirs << p.remoteDir;
}
map.insert(LOCAL_FILES_KEY, localFiles);
- map.insert(REMOTE_FILES_KEY, remoteFiles);
+ map.insert(REMOTE_DIRS_KEY, remoteDirs);
return map;
}
void MaemoPackageContents::fromMap(const QVariantMap &map)
{
m_modified = map.value(MODIFIED_KEY).toBool();
- m_remoteExecutableFilePath = map.value(REMOTE_EXE_KEY).toString();
+ m_remoteExecutableDir = map.value(REMOTE_EXE_DIR_KEY).toString();
const QStringList localFiles = map.value(LOCAL_FILES_KEY).toStringList();
- const QStringList remoteFiles = map.value(REMOTE_FILES_KEY).toStringList();
- if (localFiles.count() != remoteFiles.count())
+ const QStringList remoteDirs = map.value(REMOTE_DIRS_KEY).toStringList();
+ if (localFiles.count() != remoteDirs.count())
qWarning("%s: serialized data inconsistent", Q_FUNC_INFO);
- const int count = qMin(localFiles.count(), remoteFiles.count());
- for (int i = 0; i < count; ++i)
- m_deployables << Deployable(localFiles.at(i), remoteFiles.at(i));
+
+ QDir dir;
+ const int count = qMin(localFiles.count(), remoteDirs.count());
+ for (int i = 0; i < count; ++i) {
+ m_deployables << Deployable(dir.toNativeSeparators(localFiles.at(i)),
+ remoteDirs.at(i));
+ }
}
-QString MaemoPackageContents::remoteExecutableFilePath() const
+QString MaemoPackageContents::remoteExecutableDir() const
{
- if (m_remoteExecutableFilePath.isEmpty()) {
- m_remoteExecutableFilePath = QLatin1String("/usr/local/bin/")
- + m_packageStep->executableFileName();
+ if (m_remoteExecutableDir.isEmpty()) {
+ const Qt4ProjectType projectType
+ = m_packageStep->qt4BuildConfiguration()->qt4Target()->qt4Project()
+ ->rootProjectNode()->projectType();
+ m_remoteExecutableDir = projectType == LibraryTemplate
+ ? QLatin1String("/usr/local/lib")
+ : QLatin1String("/usr/local/bin");
}
- return m_remoteExecutableFilePath;
+ return m_remoteExecutableDir;
+}
+
+QString MaemoPackageContents::remoteExecutableFilePath() const
+{
+ return remoteExecutableDir() + '/' + m_packageStep->executableFileName();
}
} // namespace Qt4ProjectManager
public:
struct Deployable
{
- Deployable(const QString &localFilePath, const QString &remoteFilePath)
- : localFilePath(localFilePath), remoteFilePath(remoteFilePath) {}
+ Deployable(const QString &localFilePath, const QString &remoteDir)
+ : localFilePath(localFilePath), remoteDir(remoteDir) {}
bool operator==(const Deployable &other) const
{
return localFilePath == other.localFilePath
- && remoteFilePath == other.remoteFilePath;
+ && remoteDir == other.remoteDir;
}
QString localFilePath;
- QString remoteFilePath;
+ QString remoteDir;
};
MaemoPackageContents(MaemoPackageCreationStep *packageStep);
virtual bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole);
+ QString remoteExecutableDir() const;
+
private:
const MaemoPackageCreationStep * const m_packageStep;
QList<Deployable> m_deployables;
bool m_modified;
- mutable QString m_remoteExecutableFilePath;
+ mutable QString m_remoteExecutableDir;
};
} // namespace Qt4ProjectManager
for (int i = 0; i < m_packageContents->rowCount(); ++i) {
const MaemoPackageContents::Deployable &d
= m_packageContents->deployableAt(i);
- const QString targetFile = debianRoot.path() + '/' + d.remoteFilePath;
- const QString absTargetDir = QFileInfo(targetFile).dir().path();
+ const QString absTargetDir = debianRoot.path() + '/' + d.remoteDir;
+ const QString targetFile
+ = absTargetDir + '/' + QFileInfo(d.localFilePath).fileName();
const QString relTargetDir = debianRoot.relativeFilePath(absTargetDir);
if (!debianRoot.exists(relTargetDir)
&& !debianRoot.mkpath(relTargetDir)) {
->qt4Project()->rootProjectNode()->targetInformation();
if (!ti.valid)
return QString();
-
return QDir::toNativeSeparators(QDir::cleanPath(ti.workingDir
- + QLatin1Char('/') + ti.target));
+ + QLatin1Char('/') + executableFileName()));
}
QString MaemoPackageCreationStep::executableFileName() const
{
- return QFileInfo(localExecutableFilePath()).fileName();
+ const Qt4Project * const project
+ = qt4BuildConfiguration()->qt4Target()->qt4Project();
+ const TargetInformation &ti
+ = project->rootProjectNode()->targetInformation();
+ if (!ti.valid)
+ return QString();
+
+ return project->rootProjectNode()->projectType() == LibraryTemplate
+ ? QLatin1String("lib") + ti.target + QLatin1String(".so")
+ : ti.target;
}
const MaemoToolChain *MaemoPackageCreationStep::maemoToolChain() const
QString localExecutableFilePath() const;
QString executableFileName() const;
MaemoPackageContents *packageContents() const { return m_packageContents; }
+ const Qt4BuildConfiguration *qt4BuildConfiguration() const;
bool isPackagingEnabled() const { return m_packagingEnabled; }
void setPackagingEnabled(bool enabled) { m_packagingEnabled = enabled; }
bool createPackage();
bool runCommand(QProcess &proc, const QString &command);
- const Qt4BuildConfiguration *qt4BuildConfiguration() const;
const MaemoToolChain *maemoToolChain() const;
QString maddeRoot() const;
QString targetRoot() const;
m_ui(new Ui::MaemoPackageCreationWidget)
{
m_ui->setupUi(this);
+ m_ui->packageContentsView->setWordWrap(false);
m_ui->skipCheckBox->setChecked(!m_step->isPackagingEnabled());
m_ui->packageContentsView->setEnabled(m_step->isPackagingEnabled());
m_ui->packageContentsView->setModel(step->packageContents());
QTC_ASSERT(bc, return);
const QString title = tr("Choose a local file");
const QString baseDir = bc->target()->project()->projectDirectory();
- const QString localFile = QFileDialog::getOpenFileName(this, title, baseDir);
+ const QString localFile = QFileDialog::getOpenFileName(this, title, baseDir); // TODO: Support directories?
if (localFile.isEmpty())
return;
const MaemoPackageContents::Deployable
- deployable(QFileInfo(localFile).absoluteFilePath(), "/");
+ deployable(QDir::toNativeSeparators(QFileInfo(localFile).absoluteFilePath()),
+ "/");
MaemoPackageContents * const contents = m_step->packageContents();
if (!contents->addDeployable(deployable)) {
QMessageBox::information(this, tr("File already in package"),
return m_devConfig;
}
-const QString MaemoRunConfiguration::sshCmd() const
-{
- return cmd(QString::fromLocal8Bit("ssh"));
-}
-
-const QString MaemoRunConfiguration::scpCmd() const
-{
- return cmd(QString::fromLocal8Bit("scp"));
-}
-
-const QString MaemoRunConfiguration::cmd(const QString &cmdName) const
-{
- QString command(cmdName);
-#ifdef Q_OS_WIN
- command = maddeRoot() + QLatin1String("/bin/") + command
- + QLatin1String(".exe");
-#endif
- return command;
-}
-
const MaemoToolChain *MaemoRunConfiguration::toolchain() const
{
Qt4BuildConfiguration *qt4bc(activeQt4BuildConfiguration());
MaemoDeviceConfig deviceConfig() const;
QString runtimeGdbServerPort() const;
- const QString sshCmd() const;
- const QString scpCmd() const;
const QString gdbCmd() const;
const QString dumperLib() const;
private:
void init();
- const QString cmd(const QString &cmdName) const;
const MaemoToolChain *toolchain() const;
bool fileNeedsDeployment(const QString &path, const QDateTime &lastDeployed) const;
void addDeployTimesToMap(const QString &key,
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <debugger/debuggermanager.h>
+#include <debugger/debuggerrunner.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/toolchain.h>
#include <utils/qtcassert.h>
+#include <projectexplorer/projectexplorerconstants.h>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
namespace Qt4ProjectManager {
namespace Internal {
+#define USE_GDBSERVER
+
using ProjectExplorer::RunConfiguration;
using ProjectExplorer::ToolChain;
-AbstractMaemoRunControl::AbstractMaemoRunControl(RunConfiguration *rc)
- : RunControl(rc)
+AbstractMaemoRunControl::AbstractMaemoRunControl(RunConfiguration *rc, QString mode)
+ : RunControl(rc, mode)
, m_runConfig(qobject_cast<MaemoRunConfiguration *>(rc))
, m_devConfig(m_runConfig ? m_runConfig->deviceConfig() : MaemoDeviceConfig())
{
emit appendMessage(this, tr("Initial cleanup canceled by user."), false);
emit finished();
} else if (m_initialCleaner->hasError()) {
- handleError(tr("Error running initial cleanup: %1.")
+ handleError(tr("Error running initial cleanup: %1")
.arg(m_initialCleaner->error()));
emit finished();
} else {
m_needsInstall = true;
} else {
m_needsInstall = false;
- }
+ }
if (forDebugging
&& m_runConfig->debuggingHelpersNeedDeployment(m_devConfig.server.host)) {
const QFileInfo &info(m_runConfig->dumperLib());
emit appendMessage(this,
tr("Remote execution canceled due to user request."),
false);
- } else if (m_sshRunner->hasError()) {
+ } else if (m_sshRunner && m_sshRunner->hasError()) {
emit appendMessage(this, tr("Error running remote process: %1")
.arg(m_sshRunner->error()),
true);
MaemoRunControl::MaemoRunControl(RunConfiguration *runConfiguration)
- : AbstractMaemoRunControl(runConfiguration)
+ : AbstractMaemoRunControl(runConfiguration, ProjectExplorer::Constants::RUNMODE)
{
}
MaemoDebugRunControl::MaemoDebugRunControl(RunConfiguration *runConfiguration)
- : AbstractMaemoRunControl(runConfiguration)
+ : AbstractMaemoRunControl(runConfiguration, ProjectExplorer::Constants::DEBUGMODE)
, m_debuggerManager(ExtensionSystem::PluginManager::instance()
->getObject<Debugger::DebuggerManager>())
, m_startParams(new Debugger::DebuggerStartParameters)
{
QTC_ASSERT(m_debuggerManager != 0, return);
- m_startParams->startMode = Debugger::StartRemote;
+#ifdef USE_GDBSERVER
+ m_startParams->startMode = Debugger::AttachToRemote;
m_startParams->executable = executableOnHost();
+ m_startParams->debuggerCommand = m_runConfig->gdbCmd();
m_startParams->remoteChannel
= m_devConfig.server.host % QLatin1Char(':') % gdbServerPort();
m_startParams->remoteArchitecture = QLatin1String("arm");
+#else
+ m_startParams->startMode = Debugger::StartRemoteGdb;
+ m_startParams->executable = executableFilePathOnTarget();
+ m_startParams->debuggerCommand = QLatin1String("/usr/bin/gdb");
+ m_startParams->sshserver = m_devConfig.server;
+#endif
+ m_startParams->processArgs = m_runConfig->arguments();
m_startParams->sysRoot = m_runConfig->sysRoot();
m_startParams->toolChainType = ToolChain::GCC_MAEMO;
- m_startParams->debuggerCommand = m_runConfig->gdbCmd();
m_startParams->dumperLibrary = m_runConfig->dumperLib();
- m_startParams->remoteDumperLib = QString::fromLocal8Bit("%1/%2")
- .arg(remoteDir()).arg(QFileInfo(m_runConfig->dumperLib()).fileName());
+ m_startParams->remoteDumperLib = remoteDir().toUtf8() + '/'
+ + QFileInfo(m_runConfig->dumperLib()).fileName().toUtf8();
connect(m_debuggerManager, SIGNAL(debuggingFinished()), this,
SLOT(debuggingFinished()), Qt::QueuedConnection);
connect(m_debuggerManager, SIGNAL(applicationOutputAvailable(QString, bool)),
- this, SLOT(debuggerOutput(QString)), Qt::QueuedConnection);
+ this,
+#ifdef USE_GDBSERVER
+ SLOT(debuggerOutput(QString))
+#else
+ SLOT(handleRemoteOutput(QString))
+#endif
+ , Qt::QueuedConnection);
}
MaemoDebugRunControl::~MaemoDebugRunControl()
disconnect(SIGNAL(addToOutputWindow(RunControl*,QString, bool)));
disconnect(SIGNAL(addToOutputWindowInline(RunControl*,QString, bool)));
stop();
- debuggingFinished();
}
void MaemoDebugRunControl::startInternal()
.arg(executableFilePathOnTarget()).arg(targetCmdLineSuffix());
}
+void MaemoDebugRunControl::startExecution()
+{
+#ifdef USE_GDBSERVER
+ AbstractMaemoRunControl::startExecution();
+#else
+ startDebugging();
+#endif
+}
+
void MaemoDebugRunControl::handleRemoteOutput(const QString &output)
{
+#ifdef USE_GDBSERVER
if (!m_debuggingStarted) {
m_debuggingStarted = true;
startDebugging();
}
+#endif
emit addToOutputWindowInline(this, output, false);
}
void MaemoDebugRunControl::startDebugging()
{
- m_debuggerManager->startNewDebugger(m_startParams);
+ Debugger::DebuggerRunControl *runControl =
+ new Debugger::DebuggerRunControl(m_debuggerManager, *m_startParams.data());
+ m_debuggerManager->startNewDebugger(runControl);
}
void MaemoDebugRunControl::stopInternal()
void MaemoDebugRunControl::debuggingFinished()
{
+#ifdef USE_GDBSERVER
AbstractMaemoRunControl::stopRunning(true);
+#else
+ AbstractMaemoRunControl::handleRunThreadFinished();
+#endif
}
void MaemoDebugRunControl::debuggerOutput(const QString &output)
Q_OBJECT
public:
- explicit AbstractMaemoRunControl(ProjectExplorer::RunConfiguration *runConfig);
+ explicit AbstractMaemoRunControl(ProjectExplorer::RunConfiguration *runConfig, QString mode);
virtual ~AbstractMaemoRunControl();
protected:
void startDeployment(bool forDebugging);
void deploy();
void stopRunning(bool forDebugging);
- void startExecution();
+ virtual void startExecution();
void handleError(const QString &errString);
const QString executableOnHost() const;
const QString executableFileName() const;
QString packageFilePath() const;
QString executableFilePathOnTarget() const;
+protected slots:
+ void handleRunThreadFinished();
+
private slots:
virtual void handleRemoteOutput(const QString &output)=0;
void handleInitialCleanupFinished();
void handleDeployThreadFinished();
- void handleRunThreadFinished();
void handleFileCopied();
protected:
private:
virtual void startInternal();
virtual void stopInternal();
+ virtual void startExecution();
virtual QString remoteCall() const;
QString gdbServerPort() const;
void MaemoSettingsWidget::deviceTypeChanged()
{
+ const QString name = currentConfig().name;
const MaemoDeviceConfig::DeviceType devType =
m_ui->deviceButton->isChecked()
? MaemoDeviceConfig::Physical
m_lastConfigSim = currentConfig();
currentConfig() = m_lastConfigHW;
}
+ currentConfig().name = name;
fillInValues();
}
bool MaemoSshRunner::runInternal()
{
createConnection();
- connect(m_connection.data(), SIGNAL(remoteOutput(QByteArray)),
- this, SLOT(handleRemoteOutput(QByteArray)));
+ connect(m_connection.data(), SIGNAL(remoteOutputAvailable()),
+ this, SLOT(handleRemoteOutput()));
initState();
if (!m_connection->start())
return false;
m_potentialEndMarkerPrefix.clear();
}
-void MaemoSshRunner::handleRemoteOutput(const QByteArray &curOutput)
+void MaemoSshRunner::handleRemoteOutput()
{
- const QByteArray output = m_potentialEndMarkerPrefix + curOutput;
+ const QByteArray output
+ = m_potentialEndMarkerPrefix + m_connection->waitForRemoteOutput(0);
// Wait for a prompt before sending the command.
if (!m_promptEncountered) {
private:
virtual bool runInternal();
- Q_SLOT void handleRemoteOutput(const QByteArray &output);
+ Q_SLOT void handleRemoteOutput();
void initState();
static const QByteArray EndMarker;
#include <QtCore/QTextStream>
#include <QtGui/QMessageBox>
+#include <QtGui/QAction>
using namespace ProjectExplorer;
using namespace Qt4ProjectManager;
, m_needsSetup(true)
, m_userTerminated(false)
{
- Q_ASSERT(!m_instance);
- m_instance = this;
-
m_qemuStarterIcon.addFile(":/qt-maemo/images/qemu-run.png", iconSize);
m_qemuStarterIcon.addFile(":/qt-maemo/images/qemu-stop.png", iconSize,
QIcon::Normal, QIcon::On);
QemuRuntimeManager::~QemuRuntimeManager()
{
terminateRuntime();
+ m_instance = 0;
}
-QemuRuntimeManager &QemuRuntimeManager::instance()
+QemuRuntimeManager &QemuRuntimeManager::instance(QObject *parent)
{
- Q_ASSERT(m_instance);
+ if (m_instance == 0)
+ m_instance = new QemuRuntimeManager(parent);
return *m_instance;
}
Q_OBJECT
public:
- QemuRuntimeManager(QObject *parent = 0);
- ~QemuRuntimeManager();
-
- static QemuRuntimeManager& instance();
+ static QemuRuntimeManager& instance(QObject *parent = 0);
bool runtimeForQtVersion(int uniqueId, Runtime *rt) const;
void qemuStatusChanged(QemuStatus status, const QString &error);
private:
+ QemuRuntimeManager(QObject *parent);
+ ~QemuRuntimeManager();
+
void setupRuntimes();
bool sessionHasMaemoTarget() const;
switch (m_type) {
case ProjectExplorer::ToolChain::GCCE:
m_mixin.addEpocToEnvironment(&env);
+ break;
case ProjectExplorer::ToolChain::GCCE_GNUPOC:
m_mixin.addGnuPocToEnvironment(&env);
break;
using namespace Qt4ProjectManager;
RvctParser::RvctParser() :
- m_additionalInfo(false)
+ m_additionalInfo(false),
+ m_lastLine(0)
{
// Start of a error or warning:
m_warningOrError.setPattern("^\"([^\\(\\)]+[^\\d])\", line (\\d+):(\\s(Warning|Error):)\\s(.+)$");
const char * const SIGNMODE_KEY("Qt4ProjectManager.S60CreatePackageStep.SignMode");
const char * const CERTIFICATE_KEY("Qt4ProjectManager.S60CreatePackageStep.Certificate");
const char * const KEYFILE_KEY("Qt4ProjectManager.S60CreatePackageStep.Keyfile");
+ const char * const SMART_INSTALLER_KEY("Qt4ProjectManager.S60CreatorPackageStep.SmartInstaller");
}
// #pragma mark -- S60SignBuildStep
S60CreatePackageStep::S60CreatePackageStep(ProjectExplorer::BuildConfiguration *bc) :
MakeStep(bc, QLatin1String(SIGN_BS_ID)),
- m_signingMode(SignSelf)
+ m_signingMode(SignSelf),
+ m_createSmartInstaller(false)
{
ctor_package();
}
MakeStep(bc, bs),
m_signingMode(bs->m_signingMode),
m_customSignaturePath(bs->m_customSignaturePath),
- m_customKeyPath(bs->m_customKeyPath)
+ m_customKeyPath(bs->m_customKeyPath),
+ m_createSmartInstaller(bs->m_createSmartInstaller)
{
ctor_package();
}
S60CreatePackageStep::S60CreatePackageStep(ProjectExplorer::BuildConfiguration *bc, const QString &id) :
MakeStep(bc, id),
- m_signingMode(SignSelf)
+ m_signingMode(SignSelf),
+ m_createSmartInstaller(false)
{
ctor_package();
}
map.insert(QLatin1String(SIGNMODE_KEY), (int)m_signingMode);
map.insert(QLatin1String(CERTIFICATE_KEY), m_customSignaturePath);
map.insert(QLatin1String(KEYFILE_KEY), m_customKeyPath);
+ map.insert(QLatin1String(SMART_INSTALLER_KEY), m_createSmartInstaller);
return map;
}
m_signingMode = (SigningMode)map.value(QLatin1String(SIGNMODE_KEY)).toInt();
m_customSignaturePath = map.value(QLatin1String(CERTIFICATE_KEY)).toString();
m_customKeyPath = map.value(QLatin1String(KEYFILE_KEY)).toString();
+ m_createSmartInstaller = map.value(QLatin1String(SMART_INSTALLER_KEY), false).toBool();
return MakeStep::fromMap(map);
}
ProjectExplorer::Environment environment = bc->environment();
setEnvironment(environment);
QStringList args;
- args << QLatin1String("sis");
+ if (m_createSmartInstaller)
+ args << QLatin1String("installer_sis");
+ else
+ args << QLatin1String("sis");
if (signingMode() == SignCustom) {
args << QLatin1String("QT_SIS_CERTIFICATE=") + QDir::toNativeSeparators(customSignaturePath())
<< QLatin1String("QT_SIS_KEY=") + QDir::toNativeSeparators(customKeyPath());
m_customKeyPath = path;
}
+bool S60CreatePackageStep::createsSmartInstaller() const
+{
+ return m_createSmartInstaller;
+}
+
+void S60CreatePackageStep::setCreatesSmartInstaller(bool value)
+{
+ m_createSmartInstaller = value;
+ static_cast<Qt4BuildConfiguration *>(buildConfiguration())->emitS60CreatesSmartInstallerChanged();
+}
+
// #pragma mark -- S60SignBuildStepFactory
S60CreatePackageStepFactory::S60CreatePackageStepFactory(QObject *parent) :
this, SLOT(updateFromUi()));
connect(m_ui.keyFilePath, SIGNAL(changed(QString)),
this, SLOT(updateFromUi()));
+ connect(m_ui.smartInstaller, SIGNAL(clicked()),
+ this, SLOT(updateFromUi()));
}
void S60CreatePackageStepConfigWidget::updateUi()
m_ui.keyFilePath->setEnabled(!selfSigned);
m_ui.signaturePath->setPath(m_signStep->customSignaturePath());
m_ui.keyFilePath->setPath(m_signStep->customKeyPath());
+ m_ui.smartInstaller->setChecked(m_signStep->createsSmartInstaller());
emit updateSummary();
}
: S60CreatePackageStep::SignCustom);
m_signStep->setCustomSignaturePath(m_ui.signaturePath->path());
m_signStep->setCustomKeyPath(m_ui.keyFilePath->path());
+ m_signStep->setCreatesSmartInstaller(m_ui.smartInstaller->isChecked());
updateUi();
}
.arg(m_signStep->customSignaturePath())
.arg(m_signStep->customKeyPath());
}
+ if (m_signStep->createsSmartInstaller())
+ return tr("<b>Create SIS Package:</b> %1, using Smart Installer").arg(text);
return tr("<b>Create SIS Package:</b> %1").arg(text);
}
void setCustomSignaturePath(const QString &path);
QString customKeyPath() const;
void setCustomKeyPath(const QString &path);
+ bool createsSmartInstaller() const;
+ void setCreatesSmartInstaller(bool value);
protected:
S60CreatePackageStep(ProjectExplorer::BuildConfiguration *bc, S60CreatePackageStep *bs);
SigningMode m_signingMode;
QString m_customSignaturePath;
QString m_customKeyPath;
+ bool m_createSmartInstaller;
};
class S60CreatePackageStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget
<x>0</x>
<y>0</y>
<width>517</width>
- <height>95</height>
+ <height>108</height>
</rect>
</property>
<property name="windowTitle">
</layout>
</item>
<item>
+ <widget class="QCheckBox" name="smartInstaller">
+ <property name="text">
+ <string>Create Smart Installer package</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
<class>Utils::PathChooser</class>
<extends>QWidget</extends>
<header location="global">utils/pathchooser.h</header>
+ <container>1</container>
+ <slots>
+ <signal>editingFinished()</signal>
+ <signal>browsingFinished()</signal>
+ </slots>
</customwidget>
</customwidgets>
<resources/>
#include "symbiandevicemanager.h"
#include "qt4buildconfiguration.h"
#include "qt4projectmanagerconstants.h"
+#include "s60createpackagestep.h"
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
#include <projectexplorer/buildconfiguration.h>
#include <debugger/debuggermanager.h>
+#include <debugger/debuggerrunner.h>
#include <QtGui/QMessageBox>
#include <QtGui/QMainWindow>
S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *parent, const QString &proFilePath) :
RunConfiguration(parent, QLatin1String(S60_DEVICE_RC_ID)),
m_proFilePath(proFilePath),
+ m_activeBuildConfiguration(0),
#ifdef Q_OS_WIN
m_serialPortName(QLatin1String("COM5"))
#else
S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *target, S60DeviceRunConfiguration *source) :
RunConfiguration(target, source),
m_proFilePath(source->m_proFilePath),
+ m_activeBuildConfiguration(0),
m_serialPortName(source->m_serialPortName)
{
ctor();
connect(qt4Target()->qt4Project(), SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode*)),
this, SLOT(proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode*)));
+ connect(qt4Target(), SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
+ this, SLOT(updateActiveBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
+ updateActiveBuildConfiguration(qt4Target()->activeBuildConfiguration());
}
void S60DeviceRunConfiguration::proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *pro)
emit targetInformationChanged();
}
+void S60DeviceRunConfiguration::updateActiveBuildConfiguration(ProjectExplorer::BuildConfiguration *buildConfiguration)
+{
+ if (m_activeBuildConfiguration)
+ disconnect(m_activeBuildConfiguration, SIGNAL(s60CreatesSmartInstallerChanged()),
+ this, SIGNAL(targetInformationChanged()));
+ m_activeBuildConfiguration = buildConfiguration;
+ if (m_activeBuildConfiguration)
+ connect(m_activeBuildConfiguration, SIGNAL(s60CreatesSmartInstallerChanged()),
+ this, SIGNAL(targetInformationChanged()));
+}
+
S60DeviceRunConfiguration::~S60DeviceRunConfiguration()
{
}
return QDir::toNativeSeparators(localExecutable);
}
+bool S60DeviceRunConfiguration::runSmartInstaller() const
+{
+ BuildConfiguration *bc = target()->activeBuildConfiguration();
+ QTC_ASSERT(bc, return false);
+ QList<BuildStep *> steps = bc->steps(Build);
+ foreach (const BuildStep *step, steps) {
+ if (const S60CreatePackageStep *packageStep = qobject_cast<const S60CreatePackageStep *>(step)) {
+ return packageStep->createsSmartInstaller();
+ }
+ }
+ return false;
+}
+
QString S60DeviceRunConfiguration::signedPackage() const
{
TargetInformation ti = qt4Target()->qt4Project()->rootProjectNode()->targetInformation(m_proFilePath);
if (!ti.valid)
return QString();
- return ti.buildDir + QLatin1Char('/') + ti.target + QLatin1String(".sis");
+ return ti.buildDir + QLatin1Char('/') + ti.target
+ + (runSmartInstaller() ? QLatin1String("_installer") : QLatin1String(""))
+ + QLatin1String(".sis");
}
QStringList S60DeviceRunConfiguration::commandLineArguments() const
// ======== S60DeviceRunControlBase
-S60DeviceRunControlBase::S60DeviceRunControlBase(RunConfiguration *runConfiguration) :
- RunControl(runConfiguration),
+S60DeviceRunControlBase::S60DeviceRunControlBase(RunConfiguration *runConfiguration, QString mode) :
+ RunControl(runConfiguration, mode),
m_toolChain(ProjectExplorer::ToolChain::INVALID),
m_releaseDeviceAfterLauncherFinish(false),
m_handleDeviceRemoval(true),
const QString title = QCoreApplication::translate("Qt4ProjectManager::Internal::S60DeviceRunControlBase",
"Waiting for App TRK");
const QString text = QCoreApplication::translate("Qt4ProjectManager::Internal::S60DeviceRunControlBase",
- "Please start App TRK on %1.").arg(port);
+ "Qt creator waiting for the TRK application.<br>"
+ "Please make sure the application is running on "
+ "your mobile phone and the right port is "
+ "configured in the project settings.").arg(port);
QMessageBox *rc = new QMessageBox(QMessageBox::Information, title, text,
QMessageBox::Cancel, parent);
return rc;
// =============== S60DeviceRunControl
-S60DeviceRunControl::S60DeviceRunControl(ProjectExplorer::RunConfiguration *runConfiguration) :
- S60DeviceRunControlBase(runConfiguration)
+S60DeviceRunControl::S60DeviceRunControl(ProjectExplorer::RunConfiguration *runConfiguration, QString mode) :
+ S60DeviceRunControlBase(runConfiguration, mode)
{
}
// ======== S60DeviceDebugRunControl
-S60DeviceDebugRunControl::S60DeviceDebugRunControl(S60DeviceRunConfiguration *runConfiguration) :
- S60DeviceRunControlBase(runConfiguration),
+S60DeviceDebugRunControl::S60DeviceDebugRunControl(S60DeviceRunConfiguration *runConfiguration, QString mode) :
+ S60DeviceRunControlBase(runConfiguration, mode),
m_startParams(new Debugger::DebuggerStartParameters)
{
setReleaseDeviceAfterLauncherFinish(true); // Debugger controls device after install
void S60DeviceDebugRunControl::handleLauncherFinished()
{
emit appendMessage(this, tr("Launching debugger..."), false);
- Debugger::DebuggerManager::instance()->startNewDebugger(m_startParams);
+ Debugger::DebuggerManager *dm = Debugger::DebuggerManager::instance();
+ Debugger::DebuggerRunControl *runControl =
+ new Debugger::DebuggerRunControl(dm, *m_startParams.data());
+ dm->startNewDebugger(runControl);
}
void S60DeviceDebugRunControl::debuggingFinished()
private slots:
void proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *pro);
+ void updateActiveBuildConfiguration(ProjectExplorer::BuildConfiguration *buildConfiguration);
protected:
S60DeviceRunConfiguration(ProjectExplorer::Target *parent, S60DeviceRunConfiguration *source);
ProjectExplorer::ToolChain::ToolChainType toolChainType(ProjectExplorer::BuildConfiguration *configuration) const;
void ctor();
+ bool runSmartInstaller() const;
+
QString m_proFilePath;
+ ProjectExplorer::BuildConfiguration *m_activeBuildConfiguration;
QString m_serialPortName;
QStringList m_commandLineArguments;
};
{
Q_OBJECT
public:
- explicit S60DeviceRunControlBase(ProjectExplorer::RunConfiguration *runConfiguration);
+ explicit S60DeviceRunControlBase(ProjectExplorer::RunConfiguration *runConfiguration, QString mode);
~S60DeviceRunControlBase();
virtual void start();
virtual void stop();
{
Q_OBJECT
public:
- explicit S60DeviceRunControl(ProjectExplorer::RunConfiguration *runConfiguration);
+ explicit S60DeviceRunControl(ProjectExplorer::RunConfiguration *runConfiguration, QString mode);
protected:
virtual void initLauncher(const QString &executable, trk::Launcher *);
Q_DISABLE_COPY(S60DeviceDebugRunControl)
Q_OBJECT
public:
- explicit S60DeviceDebugRunControl(S60DeviceRunConfiguration *runConfiguration);
+ explicit S60DeviceDebugRunControl(S60DeviceRunConfiguration *runConfiguration, QString mode);
virtual ~S60DeviceDebugRunControl();
virtual void stop();
// ======== S60EmulatorRunControl
-S60EmulatorRunControl::S60EmulatorRunControl(S60EmulatorRunConfiguration *runConfiguration)
- : RunControl(runConfiguration)
+S60EmulatorRunControl::S60EmulatorRunControl(S60EmulatorRunConfiguration *runConfiguration, QString mode)
+ : RunControl(runConfiguration, mode)
{
// stuff like the EPOCROOT and EPOCDEVICE env variable
Environment env = Environment::systemEnvironment();
{
Q_OBJECT
public:
- explicit S60EmulatorRunControl(S60EmulatorRunConfiguration *runConfiguration);
+ explicit S60EmulatorRunControl(S60EmulatorRunConfiguration *runConfiguration, QString mode);
~S60EmulatorRunControl() {}
void start();
void stop();
ProjectExplorer::RunControl* create(ProjectExplorer::RunConfiguration *runConfiguration, const QString &mode) {
RunConfiguration *rc = qobject_cast<RunConfiguration *>(runConfiguration);
QTC_ASSERT(rc && mode == m_mode, return 0);
- return new RunControl(rc);
+ return new RunControl(rc, mode);
}
QString displayName() const {
QString Qt4BuildConfiguration::buildDirectory() const
{
QString workingDirectory;
- if (m_shadowBuild)
- workingDirectory = m_buildDirectory;
+ if (m_shadowBuild) {
+ if (!m_buildDirectory.isEmpty())
+ workingDirectory = m_buildDirectory;
+ else
+ workingDirectory = qt4Target()->defaultBuildDirectory();
+ }
if (workingDirectory.isEmpty())
workingDirectory = target()->project()->projectDirectory();
return workingDirectory;
/// \note buildDirectory() is probably the function you want to call
QString Qt4BuildConfiguration::shadowBuildDirectory() const
{
+ if (m_buildDirectory.isEmpty())
+ return qt4Target()->defaultBuildDirectory();
return m_buildDirectory;
}
emit buildDirectoryInitialized();
}
+void Qt4BuildConfiguration::emitS60CreatesSmartInstallerChanged()
+{
+ emit s60CreatesSmartInstallerChanged();
+}
+
+
void Qt4BuildConfiguration::getConfigCommandLineArguments(QStringList *addedUserConfigs, QStringList *removedUserConfigs) const
{
QtVersion::QmakeBuildConfigs defaultBuildConfiguration = qtVersion()->defaultBuildConfig();
// used by qmake step to notify that the build directory was initialized
// not really nice
void emitBuildDirectoryInitialized();
+ // used by S60CreatePackageStep to notify that the smart installer property changed
+ // not really nice
+ void emitS60CreatesSmartInstallerChanged();
+
void getConfigCommandLineArguments(QStringList *addedUserConfigs, QStringList *removedUserConfigs) const;
// Those functions are used in a few places.
/// emitted for setQMakeBuildConfig, not emitted for qt version changes, even
/// if those change the qmakebuildconfig
void qmakeBuildConfigurationChanged();
+ /// emitted when smart installer property of S60 create package step changes
+ void s60CreatesSmartInstallerChanged();
/// emitted if the build configuration changed in a way that
/// should trigger a reevaluation of all .pro files
private:
struct VersionInfo {
- VersionInfo() {}
+ VersionInfo()
+ : versionId(-1)
+ {}
VersionInfo(const QString &d, int v)
- : displayName(d), versionId(v) { }
+ : displayName(d), versionId(v)
+ {}
QString displayName;
int versionId;
};
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QCoreApplication>
+#include <QtCore/QXmlStreamReader>
#include <QtGui/QPainter>
#include <QtGui/QMainWindow>
return false;
}
+void Qt4PriFile::rename(const QString &newName)
+{
+ // Can't happen
+ Q_ASSERT(false);
+ Q_UNUSED(newName);
+}
+
QString Qt4PriFile::fileName() const
{
return m_priFile->path();
contents.updateSubFolders(this, this);
}
-QList<ProjectNode::ProjectAction> Qt4PriFileNode::supportedActions() const
+QList<ProjectNode::ProjectAction> Qt4PriFileNode::supportedActions(Node *node) const
{
QList<ProjectAction> actions;
default:
break;
}
+
+ FileNode *fileNode = qobject_cast<FileNode *>(node);
+ if (fileNode && fileNode->fileType() != ProjectExplorer::ProjectFileType)
+ actions << Rename;
+
return actions;
}
accept(&visitor);
const QStringList &allFiles = visitor.filePaths();
+ QStringList qrcFiles; // the list of qrc files referenced from ui files
+ if (fileType == ProjectExplorer::FormType) {
+ foreach (const QString &formFile, filePaths) {
+ QStringList resourceFiles = formResources(formFile);
+ foreach (const QString &resourceFile, resourceFiles)
+ if (!qrcFiles.contains(resourceFile))
+ qrcFiles.append(resourceFile);
+ }
+ }
+
+ QStringList uniqueQrcFiles;
+ foreach (const QString &file, qrcFiles) {
+ if (!allFiles.contains(file))
+ uniqueQrcFiles.append(file);
+ }
+
QStringList uniqueFilePaths;
foreach (const QString &file, filePaths) {
- if(!allFiles.contains(file))
+ if (!allFiles.contains(file))
uniqueFilePaths.append(file);
}
changeFiles(fileType, uniqueFilePaths, &failedFiles, AddToProFile);
if (notAdded)
*notAdded = failedFiles;
+ changeFiles(ProjectExplorer::ResourceType, uniqueQrcFiles, &failedFiles, AddToProFile);
+ if (notAdded)
+ *notAdded += failedFiles;
return failedFiles.isEmpty();
}
if (newFilePath.isEmpty())
return false;
- if (!QFile::rename(filePath, newFilePath))
- return false;
-
QStringList dummy;
changeFiles(fileType, QStringList() << filePath, &dummy, RemoveFromProFile);
if (!dummy.isEmpty())
return true;
}
+QStringList Qt4PriFileNode::formResources(const QString &formFile) const
+{
+ QStringList resourceFiles;
+ QFile file(formFile);
+ file.open(QIODevice::ReadOnly);
+ QXmlStreamReader reader(&file);
+
+ QFileInfo fi(formFile);
+ QDir formDir = fi.absoluteDir();
+ while (!reader.atEnd()) {
+ reader.readNext();
+ if (reader.isStartElement()) {
+ if (reader.name() == QLatin1String("iconset")) {
+ const QXmlStreamAttributes attributes = reader.attributes();
+ if (attributes.hasAttribute(QLatin1String("resource")))
+ resourceFiles.append(QDir::cleanPath(formDir.absoluteFilePath(
+ attributes.value(QLatin1String("resource")).toString())));
+ } else if (reader.name() == QLatin1String("include")) {
+ const QXmlStreamAttributes attributes = reader.attributes();
+ if (attributes.hasAttribute(QLatin1String("location")))
+ resourceFiles.append(QDir::cleanPath(formDir.absoluteFilePath(
+ attributes.value(QLatin1String("location")).toString())));
+
+ }
+ }
+ }
+
+ if (reader.hasError())
+ qWarning() << "Could not read form file:" << formFile;
+
+ return resourceFiles;
+}
+
void Qt4PriFileNode::changeFiles(const FileType fileType,
const QStringList &filePaths,
QStringList *notChanged,
// newCumalativeIt and newExactIt are already incremented
}
- // If we found something to add do it
+ // If we found something to add, do it
if (!nodeToAdd.isEmpty()) {
ProFile *fileExact = includeFilesCumlative.value(nodeToAdd);
ProFile *fileCumlative = includeFilesCumlative.value(nodeToAdd);
- if (fileExact || fileCumlative) {
+
+ // Loop preventation, make sure that exact same node is not in our parent chain
+ bool loop = false;
+ ProjectExplorer::Node *n = this;
+ while ((n = n->parentFolderNode())) {
+ if (qobject_cast<Qt4PriFileNode *>(n) && n->path() == nodeToAdd) {
+ loop = true;
+ break;
+ }
+ }
+
+ if (loop) {
+ // Do nothing
+ } else if (fileExact || fileCumlative) {
Qt4PriFileNode *qt4PriFileNode = new Qt4PriFileNode(m_project, this, nodeToAdd);
+ qt4PriFileNode->setParentFolderNode(this); // Needed for loop detection
qt4PriFileNode->update(fileExact, m_readerExact, fileCumlative, m_readerCumulative);
toAdd << qt4PriFileNode;
} else {
Qt4ProFileNode *qt4ProFileNode = new Qt4ProFileNode(m_project, nodeToAdd);
+ qt4ProFileNode->setParentFolderNode(this); // Needed for loop detection
if (async)
qt4ProFileNode->asyncUpdate();
else
Qt4PriFile(Qt4PriFileNode *qt4PriFile);
virtual bool save(const QString &fileName = QString());
virtual QString fileName() const;
+ virtual void rename(const QString &newName);
virtual QString defaultPath() const;
virtual QString suggestedFileName() const;
// ProjectNode interface
- QList<ProjectAction> supportedActions() const;
+ QList<ProjectAction> supportedActions(Node *node) const;
bool hasBuildTargets() const { return false; }
void save(const QStringList &lines);
bool priFileWritable(const QString &path);
bool saveModifiedEditors();
+ QStringList formResources(const QString &formFile) const;
QStringList baseVPaths(ProFileReader *reader, const QString &projectDir);
QStringList fullVPaths(const QStringList &baseVPaths, ProFileReader *reader, FileType type, const QString &qmakeVariable, const QString &projectDir);
return false;
}
+void Qt4ProjectFile::rename(const QString &newName)
+{
+ // Can't happen
+ Q_UNUSED(newName);
+ Q_ASSERT(false);
+}
+
QString Qt4ProjectFile::fileName() const
{
return m_filePath;
bool save(const QString &fileName = QString());
QString fileName() const;
+ virtual void rename(const QString &newName);
QString defaultPath() const;
QString suggestedFileName() const;
void Qt4Manager::buildSubDirContextMenu()
{
+ handleSubDirContexMenu(BUILD);
+}
+
+void Qt4Manager::cleanSubDirContextMenu()
+{
+ handleSubDirContexMenu(CLEAN);
+}
+
+void Qt4Manager::rebuildSubDirContextMenu()
+{
+ handleSubDirContexMenu(REBUILD);
+}
+
+void Qt4Manager::handleSubDirContexMenu(Qt4Manager::Action action)
+{
Qt4Project *qt4pro = qobject_cast<Qt4Project *>(m_contextProject);
QTC_ASSERT(qt4pro, return);
if (Qt4ProFileNode *profile = qobject_cast<Qt4ProFileNode *>(m_contextNode))
bc->setSubNodeBuild(profile);
- if (projectExplorer()->saveModifiedFiles())
- projectExplorer()->buildManager()->buildProject(bc);
+ if (projectExplorer()->saveModifiedFiles()) {
+ if (action == BUILD)
+ projectExplorer()->buildManager()->buildProject(bc);
+ else if (action == CLEAN)
+ projectExplorer()->buildManager()->cleanProject(bc);
+ else if (action == REBUILD) {
+ projectExplorer()->buildManager()->cleanProject(bc);
+ projectExplorer()->buildManager()->buildProject(bc);
+ }
+ }
bc->setSubNodeBuild(0);
}
// Return the id string of a file
static QString fileTypeId(ProjectExplorer::FileType type);
+ enum Action { BUILD, REBUILD, CLEAN };
+
public slots:
void runQMake();
void runQMakeContextMenu();
void buildSubDirContextMenu();
+ void rebuildSubDirContextMenu();
+ void cleanSubDirContextMenu();
private slots:
void editorAboutToClose(Core::IEditor *editor);
private:
QList<Qt4Project *> m_projects;
+ void handleSubDirContexMenu(Action action);
void runQMake(ProjectExplorer::Project *p, ProjectExplorer::Node *node);
Internal::Qt4ProjectManagerPlugin *m_plugin;
const char * const C_PROFILEEDITOR = ".pro File Editor";
const char * const C_PROFILEEDITOR_PANEL = ".pro File Editor (embedded)";
+// menus
+const char * const M_CONTEXT = "ProFileEditor.ContextMenu";
+
// kinds
const char * const PROJECT_ID = "Qt4.Qt4Project";
const char * const PROFILE_EDITOR_ID = "Qt4.proFileEditor";
const char * const RUNQMAKE = "Qt4Builder.RunQMake";
const char * const RUNQMAKECONTEXTMENU = "Qt4Builder.RunQMakeContextMenu";
const char * const BUILDSUBDIR = "Qt4Builder.BuildSubDir";
+const char * const REBUILDSUBDIR = "Qt4Builder.RebuildSubDir";
+const char * const CLEANSUBDIR = "Qt4Builder.CleanSubDir";
//configurations
const char * const CONFIG_DEBUG = "debug";
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/command.h>
#include <texteditor/texteditoractionhandler.h>
+#include <texteditor/texteditorconstants.h>
#ifdef WITH_TESTS
# include <QTest>
addObject(m_qt4ProjectManager);
TextEditor::TextEditorActionHandler *editorHandler
- = new TextEditor::TextEditorActionHandler(Constants::C_PROFILEEDITOR);
+ = new TextEditor::TextEditorActionHandler(Constants::C_PROFILEEDITOR,
+ TextEditor::TextEditorActionHandler::UnCommentSelection);
m_proFileEditorFactory = new ProFileEditorFactory(m_qt4ProjectManager, editorHandler);
addObject(m_proFileEditorFactory);
addAutoReleasedObject(new LinguistExternalEditor);
addAutoReleasedObject(new S60Manager);
- addAutoReleasedObject(m_maemoManager = new MaemoManager);
+ addAutoReleasedObject(new MaemoManager);
new ProFileCacheManager(this);
m_runQMakeActionContextMenu = new QAction(qmakeIcon, tr("Run qmake"), this);
command = am->registerAction(m_runQMakeActionContextMenu, Constants::RUNQMAKECONTEXTMENU, context);
command->setAttribute(Core::Command::CA_Hide);
- command->setAttribute(Core::Command::CA_UpdateText);
mproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
connect(m_runQMakeActionContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(runQMakeContextMenu()));
m_buildSubProjectContextMenu = new QAction(buildIcon, tr("Build"), this);
command = am->registerAction(m_buildSubProjectContextMenu, Constants::BUILDSUBDIR, context);
command->setAttribute(Core::Command::CA_Hide);
- command->setAttribute(Core::Command::CA_UpdateText);
msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
connect(m_buildSubProjectContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(buildSubDirContextMenu()));
+ QIcon rebuildIcon(ProjectExplorer::Constants::ICON_REBUILD);
+ rebuildIcon.addFile(ProjectExplorer::Constants::ICON_REBUILD_SMALL);
+ m_rebuildSubProjectContextMenu = new QAction(rebuildIcon, tr("Rebuild"), this);
+ command = am->registerAction(m_rebuildSubProjectContextMenu, Constants::REBUILDSUBDIR, context);
+ command->setAttribute(Core::Command::CA_Hide);
+ msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
+ connect(m_rebuildSubProjectContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(rebuildSubDirContextMenu()));
+
+ QIcon cleanIcon(ProjectExplorer::Constants::ICON_CLEAN);
+ cleanIcon.addFile(ProjectExplorer::Constants::ICON_CLEAN_SMALL);
+ m_cleanSubProjectContextMenu = new QAction(cleanIcon, tr("Clean"), this);
+ command = am->registerAction(m_cleanSubProjectContextMenu, Constants::CLEANSUBDIR, context);
+ command->setAttribute(Core::Command::CA_Hide);
+ msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
+ connect(m_cleanSubProjectContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(cleanSubDirContextMenu()));
+
connect(m_projectExplorer,
SIGNAL(aboutToShowContextMenu(ProjectExplorer::Project*, ProjectExplorer::Node*)),
this, SLOT(updateContextMenu(ProjectExplorer::Project*, ProjectExplorer::Node*)));
connect(m_projectExplorer, SIGNAL(currentProjectChanged(ProjectExplorer::Project *)),
this, SLOT(currentProjectChanged()));
+ Core::ActionContainer *contextMenu= am->createMenu(Qt4ProjectManager::Constants::M_CONTEXT);
+
+ Core::Command *cmd;
+
+ cmd = am->command(TextEditor::Constants::UN_COMMENT_SELECTION);
+ contextMenu->addAction(cmd);
+
return true;
}
void Qt4ProjectManagerPlugin::extensionsInitialized()
{
m_qt4ProjectManager->init();
- m_maemoManager->init(); // depends on the Qt4ProjectManager
}
void Qt4ProjectManagerPlugin::updateContextMenu(Project *project,
m_qt4ProjectManager->setContextNode(node);
m_runQMakeActionContextMenu->setEnabled(false);
m_buildSubProjectContextMenu->setEnabled(false);
+ m_rebuildSubProjectContextMenu->setEnabled(false);
+ m_cleanSubProjectContextMenu->setEnabled(false);
Qt4ProFileNode *proFileNode = qobject_cast<Qt4ProFileNode *>(node);
if (qobject_cast<Qt4Project *>(project) && proFileNode) {
m_runQMakeActionContextMenu->setVisible(true);
m_buildSubProjectContextMenu->setVisible(true);
-
- const QString nativeBuildDir = QDir::toNativeSeparators(proFileNode->buildDir());
- m_runQMakeActionContextMenu->setText(tr("Run qmake in %1").arg(nativeBuildDir));
- m_buildSubProjectContextMenu->setText(tr("Build in %1").arg(nativeBuildDir));
+ m_rebuildSubProjectContextMenu->setVisible(true);
+ m_cleanSubProjectContextMenu->setVisible(true);
if (!m_projectExplorer->buildManager()->isBuilding(project)) {
m_runQMakeActionContextMenu->setEnabled(true);
m_buildSubProjectContextMenu->setEnabled(true);
+ m_rebuildSubProjectContextMenu->setEnabled(true);
+ m_cleanSubProjectContextMenu->setEnabled(true);
}
} else {
m_runQMakeActionContextMenu->setVisible(false);
m_buildSubProjectContextMenu->setVisible(false);
+ m_rebuildSubProjectContextMenu->setVisible(false);
+ m_cleanSubProjectContextMenu->setVisible(false);
}
}
class MakeStepFactory;
class EmbeddedPropertiesPage;
class GettingStartedWelcomePage;
-class MaemoManager;
class Qt4ProjectManagerPlugin : public ExtensionSystem::IPlugin
{
ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
ProFileEditorFactory *m_proFileEditorFactory;
Qt4Manager *m_qt4ProjectManager;
- MaemoManager *m_maemoManager;
int m_projectContext;
QAction *m_runQMakeAction;
QAction *m_runQMakeActionContextMenu;
QAction *m_buildSubProjectContextMenu;
+ QAction *m_rebuildSubProjectContextMenu;
+ QAction *m_cleanSubProjectContextMenu;
GettingStartedWelcomePage *m_welcomePage;
};
///
QtOptionsPage::QtOptionsPage()
+ : m_widget(0)
{
}
else if (value == "build_all")
m_defaultConfigIsDebugAndRelease = true;
}
+ // Is this actually a simulator Qt?
+ if (configValues.contains(QLatin1String("simulator"))) {
+ m_targetIds.clear();
+ m_targetIds.insert(QLatin1String(Constants::QT_SIMULATOR_TARGET_ID));
+ }
delete reader;
ProFileCacheManager::instance()->decRefCount();
m_toolChainUpToDate = true;
-
- // Check qconfig.h for QT_SIMULATOR define on desktop builds and switch the
- // Qt version to Qt simulator target:
- if (m_targetIds.contains(Constants::DESKTOP_TARGET_ID)) {
- QString path(headerInstallPath());
- path.append(QLatin1String("/Qt/qconfig.h"));
- QFile qconfig(path);
- if (!qconfig.exists())
- return;
- qconfig.open(QIODevice::ReadOnly);
- QTextStream stream(&qconfig);
- QString line;
- bool isSimulator = false;
- while (!(line = stream.readLine()).isNull()) {
- if (line.startsWith(QLatin1String("#define QT_SIMULATOR"))) {
- isSimulator = true;
- break;
- }
- }
- qconfig.close();
- if (isSimulator) {
- m_targetIds.remove(QLatin1String(Constants::DESKTOP_TARGET_ID));
- m_targetIds.insert(QLatin1String(Constants::QT_SIMULATOR_TARGET_ID));
- }
- }
}
QString QtVersion::mwcDirectory() const
#include <projectexplorer/taskwindow.h>
#include <projectexplorer/toolchain.h>
-#include <QSharedPointer>
#include <QtCore/QHash>
#include <QtCore/QSet>
tr("Mobile Qt Application"),
tr("Creates a Qt application optimized for mobile devices "
"with a Qt Designer-based main window.\n\n"
- "Preselects Qt for Simulator and mobile targets if available"),
+ "Preselects Qt for Simulator and mobile targets if available."),
QIcon(QLatin1String(":/projectexplorer/images/SymbianDevice.png")),
true)
{
QTreeWidgetItem *versionItem = new QTreeWidgetItem(targetItem);
QPair<QIcon, QString> issues = reportIssues(i.version);
- QString toolTip = i.version->displayName();
+ QString toolTip = QLatin1String("<nobr>");
+ toolTip = toolTip.append(i.version->displayName());
+ toolTip.append(tr("<br>using %1", "%1: qmake used (incl. full path)").
+ arg(QDir::toNativeSeparators(i.version->qmakeCommand())));
if (!issues.second.isEmpty())
toolTip.append(QString::fromLatin1("<br><br>%1").arg(issues.second));
-<plugin name="RegExp" version="2.0.80" compatVersion="2.0.80">
+<plugin name="RegExp" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Regular Expression test widget.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
</dependencyList>
</plugin>
-<plugin name="ResourceEditor" version="2.0.80" compatVersion="2.0.80">
+<plugin name="ResourceEditor" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Editor for qrc files.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
</dependencyList>
</plugin>
return true;
}
+void ResourceEditorFile::rename(const QString &newName)
+{
+ m_parent->m_resourceEditor->setFileName(newName);
+ emit changed();
+}
+
QString ResourceEditorW::id() const {
return QLatin1String(ResourceEditor::Constants::RESOURCEEDITOR_ID);
}
QString defaultPath() const;
QString suggestedFileName() const;
virtual QString mimeType() const;
+ virtual void rename(const QString &newName);
private:
const QString m_mimeType;
-<plugin name="Snippets" version="2.0.80" compatVersion="2.0.80">
+<plugin name="Snippets" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Code snippet plugin.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
</dependencyList>
</plugin>
-<plugin name="Subversion" version="2.0.80" compatVersion="2.0.80">
+<plugin name="Subversion" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Subversion integration.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
- <dependency name="Core" version="2.0.80"/>
- <dependency name="VCSBase" version="2.0.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
+ <dependency name="Core" version="2.1.80"/>
+ <dependency name="VCSBase" version="2.1.80"/>
</dependencyList>
</plugin>
args << QLatin1String("checkout") << cwp->repository() << directory;
const QString workingDirectory = cwp->path();
*checkoutPath = workingDirectory + QLatin1Char('/') + directory;
- VCSBase::AbstractCheckoutJob *job = new VCSBase::ProcessCheckoutJob(binary, settings.addOptions(args),
+ const QStringList completeArgs = settings.hasAuthentication() ?
+ SubversionPlugin::addAuthenticationOptions(args, settings.user, settings.password) :
+ args;
+ VCSBase::AbstractCheckoutJob *job = new VCSBase::ProcessCheckoutJob(binary, completeArgs,
workingDirectory);
return QSharedPointer<VCSBase::AbstractCheckoutJob>(job);
}
switch (operation) {
case AddOperation:
case DeleteOperation:
+ case MoveOperation:
case AnnotateOperation:
break;
case OpenOperation:
return m_plugin->vcsDelete(fi.absolutePath(), fi.fileName());
}
+bool SubversionControl::vcsMove(const QString &from, const QString &to)
+{
+ const QFileInfo fromInfo(from);
+ const QFileInfo toInfo(to);
+ return m_plugin->vcsMove(fromInfo.absolutePath(), fromInfo.absoluteFilePath(), toInfo.absoluteFilePath());
+}
+
bool SubversionControl::vcsCreateRepository(const QString &)
{
return false;
return false;
}
-bool SubversionControl::managesDirectory(const QString &directory) const
-{
- return m_plugin->managesDirectory(directory);
-}
-
-QString SubversionControl::findTopLevelForDirectory(const QString &directory) const
+bool SubversionControl::managesDirectory(const QString &directory, QString *topLevel) const
{
- return m_plugin->findTopLevelForDirectory(directory);
+ return m_plugin->managesDirectory(directory, topLevel);
}
bool SubversionControl::vcsAnnotate(const QString &file, int line)
explicit SubversionControl(SubversionPlugin *plugin);
virtual QString displayName() const;
- virtual bool managesDirectory(const QString &directory) const;
- virtual QString findTopLevelForDirectory(const QString &directory) const;
+ virtual bool managesDirectory(const QString &directory, QString *topLevel = 0) const;
virtual bool supportsOperation(Operation operation) const;
virtual bool vcsOpen(const QString &fileName);
virtual bool vcsAdd(const QString &fileName);
virtual bool vcsDelete(const QString &filename);
+ virtual bool vcsMove(const QString &from, const QString &to);
virtual bool vcsCreateRepository(const QString &directory);
virtual QString vcsCreateSnapshot(const QString &topLevel);
static const char *nonInteractiveOptionC = "--non-interactive";
+
+
static const VCSBase::VCSBaseEditorParameters editorParameters[] = {
{
VCSBase::RegularCommandOutput,
QStringList args(QLatin1String("diff"));
args << files;
- const SubversionResponse response = runSvn(workingDir, args, m_settings.timeOutMS(), false, codec);
+ const SubversionResponse response =
+ runSvn(workingDir, args, m_settings.timeOutMS(), 0);
if (response.error)
return;
// NoteL: Svn "revert ." doesn not work.
QStringList args;
args << QLatin1String("revert") << QLatin1String("--recursive") << state.topLevel();
- const SubversionResponse revertResponse = runSvn(state.topLevel(), args, m_settings.timeOutMS(), true);
+ const SubversionResponse revertResponse =
+ runSvn(state.topLevel(), args, m_settings.timeOutMS(),
+ SshPasswordPrompt|ShowStdOutInLogWindow);
if (revertResponse.error) {
QMessageBox::warning(0, title, tr("Revert failed: %1").arg(revertResponse.message), QMessageBox::Ok);
} else {
QStringList args(QLatin1String("diff"));
args.push_back(state.relativeCurrentFile());
- const SubversionResponse diffResponse = runSvn(state.currentFileTopLevel(), args, m_settings.timeOutMS(), false);
+ const SubversionResponse diffResponse =
+ runSvn(state.currentFileTopLevel(), args, m_settings.timeOutMS(), 0);
if (diffResponse.error)
return;
args.clear();
args << QLatin1String("revert") << state.relativeCurrentFile();
- const SubversionResponse revertResponse = runSvn(state.currentFileTopLevel(), args, m_settings.timeOutMS(), true);
+ const SubversionResponse revertResponse =
+ runSvn(state.currentFileTopLevel(), args, m_settings.timeOutMS(),
+ SshPasswordPrompt|ShowStdOutInLogWindow);
+
if (!revertResponse.error) {
subVersionControl()->emitFilesChanged(QStringList(state.currentFile()));
}
QStringList args(QLatin1String("status"));
args += files;
- const SubversionResponse response = runSvn(workingDir, args, m_settings.timeOutMS(), false);
+ const SubversionResponse response =
+ runSvn(workingDir, args, m_settings.timeOutMS(), 0);
if (response.error)
return;
QStringList args = QStringList(QLatin1String("commit"));
args << QLatin1String(nonInteractiveOptionC) << QLatin1String("--file") << messageFile;
args.append(subVersionFileList);
- const SubversionResponse response = runSvn(m_commitRepository, args, m_settings.longTimeOutMS(), true);
+ const SubversionResponse response =
+ runSvn(m_commitRepository, args, m_settings.longTimeOutMS(),
+ SshPasswordPrompt|ShowStdOutInLogWindow);
return !response.error ;
}
args.append(relativePaths);
VCSBase::VCSBaseOutputWindow *outwin = VCSBase::VCSBaseOutputWindow::instance();
outwin->setRepository(workingDir);
- runSvn(workingDir, args, m_settings.timeOutMS(), true);
+ runSvn(workingDir, args, m_settings.timeOutMS(),
+ ShowStdOutInLogWindow);
outwin->clearRepository();
}
foreach(const QString &file, files)
args.append(QDir::toNativeSeparators(file));
- const SubversionResponse response = runSvn(workingDir, args, m_settings.timeOutMS(), false, codec);
+ const SubversionResponse response =
+ runSvn(workingDir, args, m_settings.timeOutMS(),
+ SshPasswordPrompt, codec);
if (response.error)
return;
args.push_back(QLatin1String(nonInteractiveOptionC));
if (!relativePaths.isEmpty())
args.append(relativePaths);
- const SubversionResponse response = runSvn(workingDir, args, m_settings.longTimeOutMS(), true);
+ const SubversionResponse response =
+ runSvn(workingDir, args, m_settings.longTimeOutMS(),
+ SshPasswordPrompt|ShowStdOutInLogWindow);
if (!response.error)
subVersionControl()->emitRepositoryChanged(workingDir);
}
args.push_back(QLatin1String("-v"));
args.append(QDir::toNativeSeparators(file));
- const SubversionResponse response = runSvn(workingDir, args, m_settings.timeOutMS(), false, codec);
+ const SubversionResponse response =
+ runSvn(workingDir, args, m_settings.timeOutMS(),
+ SshPasswordPrompt, codec);
if (response.error)
return;
// To describe a complete change, find the top level and then do
//svn diff -r 472958:472959 <top level>
const QFileInfo fi(source);
- const QString topLevel = findTopLevelForDirectory(fi.isDir() ? source : fi.absolutePath());
- if (topLevel.isEmpty())
+ QString topLevel;
+ const bool manages = managesDirectory(fi.isDir() ? source : fi.absolutePath(), &topLevel);
+ if (!manages || topLevel.isEmpty())
return;
if (Subversion::Constants::debug)
qDebug() << Q_FUNC_INFO << source << topLevel << changeNr;
QStringList args(QLatin1String("log"));
args.push_back(QLatin1String("-r"));
args.push_back(changeNr);
- const SubversionResponse logResponse = runSvn(topLevel, args, m_settings.timeOutMS(), false);
+ const SubversionResponse logResponse =
+ runSvn(topLevel, args, m_settings.timeOutMS(), SshPasswordPrompt);
if (logResponse.error)
return;
description = logResponse.stdOut;
args.push_back(diffArg);
QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(source);
- const SubversionResponse response = runSvn(topLevel, args, m_settings.timeOutMS(), false, codec);
+ const SubversionResponse response =
+ runSvn(topLevel, args, m_settings.timeOutMS(),
+ SshPasswordPrompt, codec);
if (response.error)
return;
description += response.stdOut;
<< Core::EditorManager::instance()->currentEditor());
}
-static inline QString processStdErr(QProcess &proc)
+SubversionResponse
+ SubversionPlugin::runSvn(const QString &workingDir,
+ const QStringList &arguments,
+ int timeOut,
+ unsigned flags,
+ QTextCodec *outputCodec)
{
- 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'));
+ return m_settings.hasAuthentication() ?
+ runSvn(workingDir, m_settings.user, m_settings.password,
+ arguments, timeOut, flags, outputCodec) :
+ runSvn(workingDir, QString(), QString(),
+ arguments, timeOut, flags, outputCodec);
}
-// Format log entry for command
-static inline QString msgExecutionLogEntry(const QString &workingDir, const QString &executable, const QStringList &arguments)
+// Add authorization options to the command line arguments.
+// SVN pre 1.5 does not accept "--userName" for "add", which is most likely
+// an oversight. As no password is needed for the option, generally omit it.
+QStringList SubversionPlugin::addAuthenticationOptions(const QStringList &args,
+ const QString &userName, const QString &password)
{
- const QString argsS = SubversionSettings::formatArguments(arguments);
- if (workingDir.isEmpty())
- return SubversionPlugin::tr("Executing: %1 %2\n").arg(executable, argsS);
- return SubversionPlugin::tr("Executing in %1: %2 %3\n").
- arg(QDir::toNativeSeparators(workingDir), executable, argsS);
+ if (userName.isEmpty())
+ return args;
+ if (!args.empty() && args.front() == QLatin1String("add"))
+ return args;
+ QStringList rc;
+ rc.push_back(QLatin1String("--username"));
+ rc.push_back(userName);
+ if (!password.isEmpty()) {
+ rc.push_back(QLatin1String("--password"));
+ rc.push_back(password);
+ }
+ rc.append(args);
+ return rc;
}
SubversionResponse SubversionPlugin::runSvn(const QString &workingDir,
- const QStringList &arguments,
- int timeOut,
- bool showStdOutInOutputWindow,
- QTextCodec *outputCodec)
+ const QString &userName, const QString &password,
+ const QStringList &arguments, int timeOut,
+ unsigned flags, QTextCodec *outputCodec)
{
const QString executable = m_settings.svnCommand;
SubversionResponse response;
response.message =tr("No subversion executable specified!");
return response;
}
- const QStringList allArgs = m_settings.addOptions(arguments);
-
- VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
- // Hide passwords, etc in the log window
- //: Executing: <executable> <arguments>
- const QString outputText = msgExecutionLogEntry(workingDir, executable, allArgs);
- outputWindow->appendCommand(outputText);
- if (Subversion::Constants::debug)
- qDebug() << "runSvn" << timeOut << outputText;
-
- // Run, connect stderr to the output window
- Utils::SynchronousProcess process;
- if (!workingDir.isEmpty())
- process.setWorkingDirectory(workingDir);
- QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
- env.insert(QLatin1String("LANG"), QString(QLatin1Char('C')));
- process.setProcessEnvironment(env);
- process.setTimeout(timeOut);
- process.setStdOutCodec(outputCodec);
-
- process.setStdErrBufferedSignalsEnabled(true);
- connect(&process, SIGNAL(stdErrBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
-
- // connect stdout to the output window if desired
- if (showStdOutInOutputWindow) {
- process.setStdOutBufferedSignalsEnabled(true);
- connect(&process, SIGNAL(stdOutBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
- }
+ const QStringList completeArguments = SubversionPlugin::addAuthenticationOptions(arguments, userName, password);
+ const Utils::SynchronousProcessResponse sp_resp =
+ VCSBase::VCSBasePlugin::runVCS(workingDir, executable,
+ completeArguments, timeOut, flags, outputCodec);
- const Utils::SynchronousProcessResponse sp_resp = process.run(executable, allArgs);
- response.error = true;
+ response.error = sp_resp.result != Utils::SynchronousProcessResponse::Finished;
+ if (response.error)
+ response.message = sp_resp.exitMessage(executable, timeOut);
response.stdErr = sp_resp.stdErr;
response.stdOut = sp_resp.stdOut;
- switch (sp_resp.result) {
- case Utils::SynchronousProcessResponse::Finished:
- response.error = false;
- break;
- case Utils::SynchronousProcessResponse::FinishedError:
- response.message = tr("The process terminated with exit code %1.").arg(sp_resp.exitCode);
- break;
- case Utils::SynchronousProcessResponse::TerminatedAbnormally:
- response.message = tr("The process terminated abnormally.");
- break;
- case Utils::SynchronousProcessResponse::StartFailed:
- response.message = tr("Could not start subversion '%1'. Please check your settings in the preferences.").arg(executable);
- break;
- case Utils::SynchronousProcessResponse::Hang:
- response.message = tr("Subversion did not respond within timeout limit (%1 ms).").arg(timeOut);
- break;
- }
- if (response.error)
- outputWindow->appendError(response.message);
-
return response;
}
const QString file = QDir::toNativeSeparators(rawFileName);
QStringList args;
args << QLatin1String("add") << QLatin1String("--parents") << file;
- const SubversionResponse response = runSvn(workingDir, args, m_settings.timeOutMS(), true);
+ const SubversionResponse response =
+ runSvn(workingDir, args, m_settings.timeOutMS(),
+ SshPasswordPrompt|ShowStdOutInLogWindow);
return !response.error;
}
if (!path.isEmpty())
path += slash;
path += relativePath.at(p);
- if (!managesDirectory(QDir(path))) {
+ if (!checkSVNSubDir(QDir(path))) {
QStringList addDirArgs;
addDirArgs << QLatin1String("add") << QLatin1String("--non-recursive") << QDir::toNativeSeparators(path);
- const SubversionResponse addDirResponse = runSvn(workingDir, addDirArgs, m_settings.timeOutMS(), true);
+ const SubversionResponse addDirResponse =
+ runSvn(workingDir, addDirArgs, m_settings.timeOutMS(),
+ SshPasswordPrompt|ShowStdOutInLogWindow);
if (addDirResponse.error)
return false;
}
// Add file
QStringList args;
args << QLatin1String("add") << QDir::toNativeSeparators(rawFileName);
- const SubversionResponse response = runSvn(workingDir, args, m_settings.timeOutMS(), true);
+ const SubversionResponse response =
+ runSvn(workingDir, args, m_settings.timeOutMS(),
+ SshPasswordPrompt|ShowStdOutInLogWindow);
return !response.error;
}
QStringList args(QLatin1String("delete"));
args.push_back(file);
- const SubversionResponse response = runSvn(workingDir, args, m_settings.timeOutMS(), true);
+ const SubversionResponse response =
+ runSvn(workingDir, args, m_settings.timeOutMS(),
+ SshPasswordPrompt|ShowStdOutInLogWindow);
+ return !response.error;
+}
+
+bool SubversionPlugin::vcsMove(const QString &workingDir, const QString &from, const QString &to)
+{
+ QStringList args(QLatin1String("move"));
+ args << QDir::toNativeSeparators(from) << QDir::toNativeSeparators(to);
+ qDebug()<<args;
+ const SubversionResponse response =
+ runSvn(workingDir, args, m_settings.timeOutMS(),
+ SshPasswordPrompt|ShowStdOutInLogWindow);
+ qDebug() << response.stdOut << "\n"<<response.stdErr;
return !response.error;
}
/* Subversion has ".svn" directory in each directory
* it manages. The top level is the first directory
* under the directory that does not have a ".svn". */
-bool SubversionPlugin::managesDirectory(const QString &directory) const
+bool SubversionPlugin::managesDirectory(const QString &directory, QString *topLevel /* = 0 */) const
{
const QDir dir(directory);
- const bool rc = dir.exists() && managesDirectory(dir);
- if (Subversion::Constants::debug)
- qDebug() << "SubversionPlugin::managesDirectory" << directory << rc;
- return rc;
+ if (topLevel)
+ topLevel->clear();
+ bool manages = false;
+ do {
+ if (!dir.exists() || !checkSVNSubDir(dir))
+ break;
+ manages = true;
+ if (!topLevel)
+ break;
+ /* Recursing up, the top level is a child of the first directory that does
+ * not have a ".svn" directory. The starting directory must be a managed
+ * one. Go up and try to find the first unmanaged parent dir. */
+ QDir lastDirectory = dir;
+ for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) {
+ if (!checkSVNSubDir(parentDir)) {
+ *topLevel = lastDirectory.absolutePath();
+ break;
+ }
+ }
+ } while (false);
+ if (Subversion::Constants::debug) {
+ QDebug nsp = qDebug().nospace();
+ nsp << "SubversionPlugin::managesDirectory" << directory << manages;
+ if (topLevel)
+ nsp << *topLevel;
+ }
+ return manages;
}
-bool SubversionPlugin::managesDirectory(const QDir &directory) const
+// Check whether SVN management subdirs exist.
+bool SubversionPlugin::checkSVNSubDir(const QDir &directory) const
{
const int dirCount = m_svnDirectories.size();
for (int i = 0; i < dirCount; i++) {
return false;
}
-QString SubversionPlugin::findTopLevelForDirectory(const QString &directory) const
-{
- // Debug wrapper
- const QString rc = findTopLevelForDirectoryI(directory);
- if (Subversion::Constants::debug)
- qDebug() << "SubversionPlugin::findTopLevelForDirectory" << directory << rc;
- return rc;
-}
-
-QString SubversionPlugin::findTopLevelForDirectoryI(const QString &directory) const
-{
- /* Recursing up, the top level is a child of the first directory that does
- * not have a ".svn" directory. The starting directory must be a managed
- * one. Go up and try to find the first unmanaged parent dir. */
- QDir lastDirectory = QDir(directory);
- if (!lastDirectory.exists() || !managesDirectory(lastDirectory))
- return QString();
- for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) {
- if (!managesDirectory(parentDir))
- return lastDirectory.absolutePath();
- }
- return QString();
-}
-
SubversionControl *SubversionPlugin::subVersionControl() const
{
return static_cast<SubversionControl *>(versionControl());
bool vcsAdd14(const QString &workingDir, const QString &fileName);
bool vcsAdd15(const QString &workingDir, const QString &fileName);
bool vcsDelete(const QString &workingDir, const QString &fileName);
- bool managesDirectory(const QString &directory) const;
- QString findTopLevelForDirectory(const QString &directory) const;
+ bool vcsMove(const QString &workingDir, const QString &from, const QString &to);
+ bool managesDirectory(const QString &directory, QString *topLevel = 0) const;
static SubversionPlugin *subversionPluginInstance();
+ // Add authorization options to the command line arguments.
+ static QStringList addAuthenticationOptions(const QStringList &args,
+ const QString &userName = QString(),
+ const QString &password = QString());
+
public slots:
void vcsAnnotate(const QString &workingDir, const QString &file,
const QString &revision = QString(), int lineNumber = -1);
Core::IEditor * showOutputInEditor(const QString& title, const QString &output,
int editorType, const QString &source,
QTextCodec *codec);
+ // Run using the settings' authentication options.
+ SubversionResponse runSvn(const QString &workingDir,
+ const QStringList &arguments, int timeOut,
+ unsigned flags, QTextCodec *outputCodec = 0);
+ // Run using custom authentication options.
SubversionResponse runSvn(const QString &workingDir,
+ const QString &userName, const QString &password,
const QStringList &arguments, int timeOut,
- bool showStdOutInOutputWindow, QTextCodec *outputCodec = 0);
+ unsigned flags, QTextCodec *outputCodec = 0);
+
void filelog(const QString &workingDir,
const QStringList &file = QStringList(),
bool enableAnnotationContextMenu = false);
void svnStatus(const QString &workingDir, const QStringList &relativePath = QStringList());
void svnUpdate(const QString &workingDir, const QStringList &relativePaths = QStringList());
- bool managesDirectory(const QDir &directory) const;
- QString findTopLevelForDirectoryI(const QString &directory) const;
+ bool checkSVNSubDir(const QDir &directory) const;
void startCommit(const QString &workingDir, const QStringList &files = QStringList());
bool commit(const QString &messageFile, const QStringList &subVersionFileList);
void cleanCommitMessageFile();
#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 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 const char *promptToSubmitKeyC = "PromptForSubmit";
-static const char *timeOutKeyC = "TimeOut";
-static const char *spaceIgnorantAnnotationKeyC = "SpaceIgnorantAnnotation";
-static const char *logCountKeyC = "LogCount";
+static const char promptToSubmitKeyC[] = "PromptForSubmit";
+static const char timeOutKeyC[] = "TimeOut";
+static const char spaceIgnorantAnnotationKeyC[] = "SpaceIgnorantAnnotation";
+static const char logCountKeyC[] = "LogCount";
enum { defaultTimeOutS = 30, defaultLogCount = 1000 };
&& promptToSubmit == s.promptToSubmit
&& spaceIgnorantAnnotation == s.spaceIgnorantAnnotation;
}
-
-QStringList SubversionSettings::addOptions(const QStringList &args) const
-{
- if (!useAuthentication || user.isEmpty())
- return args;
- // SVN pre 1.5 does not accept "--userName" for "add", which is most likely
- // an oversight. As no password is needed for the option, generally omit it.
- if (!args.empty() && args.front() == QLatin1String("add"))
- 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;
-}
namespace Subversion {
namespace Internal {
-// Todo: Add user name and password?
struct SubversionSettings
{
SubversionSettings();
inline int timeOutMS() const { return timeOutS * 1000; }
inline int longTimeOutMS() const { return timeOutS * 10000; }
- // 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);
+ inline bool hasAuthentication() const { return useAuthentication && !user.isEmpty(); }
bool equals(const SubversionSettings &s) const;
<glob pattern="*.txt"/>
</mime-type>
<mime-type type="application/xml">
+ <alias type="text/xml"/>
<sub-class-of type="text/plain"/>
<comment>XML document</comment>
<glob pattern="*.xml"/>
-<plugin name="TextEditor" version="2.0.80" compatVersion="2.0.80">
+<plugin name="TextEditor" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Text editor framework and the implementation of the basic text editor.</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
- <dependency name="Find" version="2.0.80"/>
- <dependency name="Locator" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
+ <dependency name="Find" version="2.1.80"/>
+ <dependency name="Locator" version="2.1.80"/>
</dependencyList>
</plugin>
result.lineNumber,
result.matchingLine,
result.matchStart,
- result.matchLength);
+ result.matchLength,
+ result.regexpCapturedTexts);
if (m_resultLabel)
m_resultLabel->setText(tr("%1 found").arg(m_resultWindow->numberOfResults()));
}
static void applyChanges(QTextDocument *doc, const QString &text, const QList<Find::SearchResultItem> &items)
{
- QList<QTextCursor> cursors;
+ QList<QPair<QTextCursor, QString> > changes;
foreach (const Find::SearchResultItem &item, items) {
const int blockNumber = item.lineNumber - 1;
const int cursorPosition = tc.position() + item.searchTermStart;
int cursorIndex = 0;
- for (; cursorIndex < cursors.size(); ++cursorIndex) {
- const QTextCursor &tc = cursors.at(cursorIndex);
+ for (; cursorIndex < changes.size(); ++cursorIndex) {
+ const QTextCursor &otherTc = changes.at(cursorIndex).first;
- if (tc.position() == cursorPosition)
+ if (otherTc.position() == cursorPosition)
break;
}
- if (cursorIndex != cursors.size())
+ if (cursorIndex != changes.size())
continue; // skip this change.
tc.setPosition(cursorPosition);
tc.setPosition(tc.position() + item.searchTermLength,
QTextCursor::KeepAnchor);
- cursors.append(tc);
+ QString substitutionText;
+ if (item.userData.canConvert<QStringList>() && !item.userData.toStringList().isEmpty())
+ substitutionText = Utils::expandRegExpReplacement(text, item.userData.toStringList());
+ else
+ substitutionText = text;
+ changes.append(QPair<QTextCursor, QString>(tc, substitutionText));
}
- foreach (QTextCursor tc, cursors)
- tc.insertText(text);
+ for (int i = 0; i < changes.size(); ++i) {
+ QPair<QTextCursor, QString> &cursor = changes[i];
+ cursor.first.insertText(cursor.second);
+ }
}
QStringList BaseFileFind::replaceAll(const QString &text,
it.next();
const QString fileName = it.key();
- const QList<Find::SearchResultItem> items = it.value();
+ const QList<Find::SearchResultItem> changeItems = it.value();
const QList<Core::IEditor *> editors = editorManager->editorsForFileName(fileName);
TextEditor::BaseTextEditor *textEditor = 0;
if (textEditor != 0) {
QTextCursor tc = textEditor->textCursor();
tc.beginEditBlock();
- applyChanges(textEditor->document(), text, items);
+ applyChanges(textEditor->document(), text, changeItems);
tc.endEditBlock();
} else {
QFile file(fileName);
QTextDocument doc;
doc.setPlainText(plainText);
- applyChanges(&doc, text, items);
+ applyChanges(&doc, text, changeItems);
QFile newFile(fileName);
if (newFile.open(QFile::WriteOnly)) {
/* returns the list of unique files that were passed in items */
static QStringList replaceAll(const QString &txt,
const QList<Find::SearchResultItem> &items);
+
protected:
virtual QStringList files() = 0;
void writeCommonSettings(QSettings *settings);
return true;
}
+void BaseTextDocument::rename(const QString &newName)
+{
+ const QFileInfo fi(newName);
+ m_fileName = QDir::cleanPath(fi.absoluteFilePath());
+ emit titleChanged(fi.fileName());
+ emit changed();
+}
+
bool BaseTextDocument::isReadOnly() const
{
if (m_isBinaryData || m_hasDecodingError)
void reload(ReloadFlag flag, ChangeType type);
virtual QString mimeType() const;
void setMimeType(const QString &mt);
+ virtual void rename(const QString &newName);
virtual QString defaultPath() const { return m_defaultPath; }
virtual QString suggestedFileName() const { return m_suggestedFileName; }
using namespace TextEditor;
-bool Parenthesis::hasClosingCollapse(const Parentheses &parentheses)
-{
- return closeCollapseAtPos(parentheses) >= 0;
-}
-
-int Parenthesis::closeCollapseAtPos(const Parentheses &parentheses)
-{
- int depth = 0;
- for (int i = 0; i < parentheses.size(); ++i) {
- const Parenthesis &p = parentheses.at(i);
- if (p.chr == QLatin1Char('{')
- || p.chr == QLatin1Char('+')
- || p.chr == QLatin1Char('[')) {
- ++depth;
- } else if (p.chr == QLatin1Char('}')
- || p.chr == QLatin1Char('-')
- || p.chr == QLatin1Char(']')) {
- if (--depth < 0)
- return p.pos;
- }
- }
- return -1;
-}
-
-int Parenthesis::collapseAtPos(const Parentheses &parentheses, QChar *character)
-{
- int result = -1;
- QChar c;
-
- int depth = 0;
- for (int i = 0; i < parentheses.size(); ++i) {
- const Parenthesis &p = parentheses.at(i);
- if (p.chr == QLatin1Char('{')
- || p.chr == QLatin1Char('+')
- || p.chr == QLatin1Char('[')) {
- if (depth == 0) {
- result = p.pos;
- c = p.chr;
- }
- ++depth;
- } else if (p.chr == QLatin1Char('}')
- || p.chr == QLatin1Char('-')
- || p.chr == QLatin1Char(']')) {
- if (--depth < 0)
- depth = 0;
- result = -1;
- }
- }
- if (result >= 0 && character)
- *character = c;
- return result;
-}
-
-
TextBlockUserData::~TextBlockUserData()
{
TextMarks marks = m_marks;
}
}
-int TextBlockUserData::collapseAtPos(QChar *character) const
-{
- return Parenthesis::collapseAtPos(m_parentheses, character);
-}
-
int TextBlockUserData::braceDepthDelta() const
{
int delta = 0;
return delta;
}
-
-QTextBlock TextBlockUserData::testCollapse(const QTextBlock& block)
-{
- QTextBlock info = block;
- if (block.userData() && static_cast<TextBlockUserData*>(block.userData())->collapseMode() == CollapseAfter)
- ;
- else if (block.next().userData()
- && static_cast<TextBlockUserData*>(block.next().userData())->collapseMode()
- == TextBlockUserData::CollapseThis)
- info = block.next();
- else
- return QTextBlock();
- int pos = static_cast<TextBlockUserData*>(info.userData())->collapseAtPos();
- if (pos < 0)
- return QTextBlock();
- QTextCursor cursor(info);
- cursor.setPosition(cursor.position() + pos);
- matchCursorForward(&cursor);
- return cursor.block();
-}
-
-void TextBlockUserData::doCollapse(const QTextBlock& block, bool visible)
-{
- QTextBlock info = block;
- if (block.userData() && static_cast<TextBlockUserData*>(block.userData())->collapseMode() == CollapseAfter)
- ;
- else if (block.next().userData()
- && static_cast<TextBlockUserData*>(block.next().userData())->collapseMode()
- == TextBlockUserData::CollapseThis)
- info = block.next();
- else {
- if (visible && !block.next().isVisible()) {
- // no match, at least unfold!
- QTextBlock b = block.next();
- while (b.isValid() && !b.isVisible()) {
- b.setVisible(true);
- b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0);
- b = b.next();
- }
- }
- return;
- }
- int pos = static_cast<TextBlockUserData*>(info.userData())->collapseAtPos();
- if (pos < 0)
- return;
- QTextCursor cursor(info);
- cursor.setPosition(cursor.position() + pos);
- if (matchCursorForward(&cursor) != Match) {
- if (visible) {
- // no match, at least unfold!
- QTextBlock b = block.next();
- while (b.isValid() && !b.isVisible()) {
- b.setVisible(true);
- b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0);
- b = b.next();
- }
- }
- return;
- }
-
- QTextBlock b = block.next();
- while (b < cursor.block()) {
- b.setVisible(visible);
- b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0);
- if (visible) {
- TextBlockUserData *data = canCollapse(b);
- if (data && data->collapsed()) {
- QTextBlock end = testCollapse(b);
- if (data->collapseIncludesClosure())
- end = end.next();
- if (end.isValid()) {
- b = end;
- continue;
- }
- }
- }
- b = b.next();
- }
-
- bool collapseIncludesClosure = hasClosingCollapseAtEnd(b);
- if (collapseIncludesClosure) {
- b.setVisible(visible);
- b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0);
- }
- static_cast<TextBlockUserData*>(info.userData())->setCollapseIncludesClosure(collapseIncludesClosure);
- static_cast<TextBlockUserData*>(info.userData())->setCollapsed(!block.next().isVisible());
-
-}
-
-
TextBlockUserData::MatchType TextBlockUserData::checkOpenParenthesis(QTextCursor *cursor, QChar c)
{
QTextBlock block = cursor->block();
if (delta)
setBraceDepth(block, braceDepth(block) + delta);
}
+
+void BaseTextDocumentLayout::setFoldingIndent(const QTextBlock &block, int indent)
+{
+ if (indent == 0) {
+ if (TextBlockUserData *userData = testUserData(block))
+ userData->setFoldingIndent(0);
+ } else {
+ userData(block)->setFoldingIndent(qMax(0,indent));
+ }
+}
+
+int BaseTextDocumentLayout::foldingIndent(const QTextBlock &block)
+{
+ if (TextBlockUserData *userData = testUserData(block))
+ return userData->foldingIndent();
+ return 0;
+}
+
+void BaseTextDocumentLayout::changeFoldingIndent(QTextBlock &block, int delta)
+{
+ if (delta)
+ setFoldingIndent(block, foldingIndent(block) + delta);
+}
+
+bool BaseTextDocumentLayout::canFold(const QTextBlock &block)
+{
+ return (block.next().isValid() && foldingIndent(block.next()) > foldingIndent(block));
+}
+
+bool BaseTextDocumentLayout::isFolded(const QTextBlock &block)
+{
+ if (TextBlockUserData *userData = testUserData(block))
+ return userData->folded();
+ return false;
+}
+
+void BaseTextDocumentLayout::setFolded(const QTextBlock &block, bool folded)
+{
+ if (folded)
+ userData(block)->setFolded(true);
+ else {
+ if (TextBlockUserData *userData = testUserData(block))
+ return userData->setFolded(false);
+ }
+}
+
+void BaseTextDocumentLayout::doFoldOrUnfold(const QTextBlock& block, bool unfold)
+{
+ if (!canFold(block))
+ return;
+ QTextBlock b = block.next();
+
+ int indent = foldingIndent(block);
+ while (b.isValid() && foldingIndent(b) > indent && b.next().isValid()) {
+ b.setVisible(unfold);
+ b.setLineCount(unfold? qMax(1, b.layout()->lineCount()) : 0);
+ if (unfold) { // do not unfold folded sub-blocks
+ if (isFolded(b) && b.next().isValid()) {
+ int jndent = foldingIndent(b);
+ b = b.next();
+ while (b.isValid() && foldingIndent(b) > jndent)
+ b = b.next();
+ continue;
+ }
+ }
+ b = b.next();
+ }
+ setFolded(block, !unfold);
+}
+
+
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);
};
{
public:
- enum CollapseMode { NoCollapse , CollapseThis, CollapseAfter };
- enum ClosingCollapseMode { NoClosingCollapse, ClosingCollapse, ClosingCollapseAtEnd };
-
inline TextBlockUserData()
- : m_collapseIncludesClosure(false),
- m_collapseMode(NoCollapse),
- m_closingCollapseMode(NoClosingCollapse),
- m_collapsed(false),
- m_ifdefedOut(false) {}
+ : m_folded(false),
+ m_ifdefedOut(false),
+ m_foldingIndent(0),
+ m_foldingStartIncluded(false),
+ m_foldingEndIncluded(false){}
~TextBlockUserData();
inline TextMarks marks() const { return m_marks; }
inline void clearMarks() { m_marks.clear(); }
inline void documentClosing() { Q_FOREACH(ITextMark *tm, m_marks) { tm->documentClosing(); } m_marks.clear();}
- inline CollapseMode collapseMode() const { return (CollapseMode)m_collapseMode; }
- inline void setCollapseMode(CollapseMode c) { m_collapseMode = c; }
-
- inline void setClosingCollapseMode(ClosingCollapseMode c) { m_closingCollapseMode = c; }
- inline ClosingCollapseMode closingCollapseMode() const { return (ClosingCollapseMode) m_closingCollapseMode; }
-
- inline bool hasClosingCollapse() const { return closingCollapseMode() != NoClosingCollapse; }
- inline bool hasClosingCollapseAtEnd() const { return closingCollapseMode() == ClosingCollapseAtEnd; }
- inline bool hasClosingCollapseInside() const { return closingCollapseMode() == ClosingCollapse; }
-
- inline void setCollapsed(bool b) { m_collapsed = b; }
- inline bool collapsed() const { return m_collapsed; }
-
- inline void setCollapseIncludesClosure(bool b) { m_collapseIncludesClosure = b; }
- inline bool collapseIncludesClosure() const { return m_collapseIncludesClosure; }
+ inline void setFolded(bool b) { m_folded = b; }
+ inline bool folded() const { return m_folded; }
inline void setParentheses(const Parentheses &parentheses) { m_parentheses = parentheses; }
inline void clearParentheses() { m_parentheses.clear(); }
inline bool clearIfdefedOut() { bool result = m_ifdefedOut; m_ifdefedOut = false; return result;}
inline bool ifdefedOut() const { return m_ifdefedOut; }
- inline static TextBlockUserData *canCollapse(const QTextBlock &block) {
- TextBlockUserData *data = static_cast<TextBlockUserData*>(block.userData());
- if (!data || data->collapseMode() != CollapseAfter) {
- data = static_cast<TextBlockUserData*>(block.next().userData());
- if (!data || data->collapseMode() != TextBlockUserData::CollapseThis)
- data = 0;
- }
- if (data && data->m_ifdefedOut)
- data = 0;
- return data;
- }
-
- inline static bool hasCollapseAfter(const QTextBlock & block)
- {
- if (!block.isValid()) {
- return false;
- } else if (block.next().isValid()) {
- TextBlockUserData *data = static_cast<TextBlockUserData*>(block.next().userData());
- if (data && data->collapseMode() == TextBlockUserData::CollapseThis && !data->m_ifdefedOut)
- return true;
- }
- return false;
- }
-
- inline static bool hasClosingCollapse(const QTextBlock &block) {
- TextBlockUserData *data = static_cast<TextBlockUserData*>(block.userData());
- return (data && data->hasClosingCollapse());
- }
-
- inline static bool hasClosingCollapseAtEnd(const QTextBlock &block) {
- TextBlockUserData *data = static_cast<TextBlockUserData*>(block.userData());
- return (data && data->hasClosingCollapseAtEnd());
- }
-
- inline static bool hasClosingCollapseInside(const QTextBlock &block) {
- TextBlockUserData *data = static_cast<TextBlockUserData*>(block.userData());
- return (data && data->hasClosingCollapseInside());
- }
-
- static QTextBlock testCollapse(const QTextBlock& block);
- static void doCollapse(const QTextBlock& block, bool visible);
-
- int collapseAtPos(QChar *character = 0) const;
enum MatchType { NoMatch, Match, Mismatch };
static MatchType checkOpenParenthesis(QTextCursor *cursor, QChar c);
static bool findPreviousBlockOpenParenthesis(QTextCursor *cursor, bool checkStartPosition = false);
static bool findNextBlockClosingParenthesis(QTextCursor *cursor);
+ int foldingIndent() const { return m_foldingIndent; }
+ void setFoldingIndent(int indent) { m_foldingIndent = indent; }
+ void setFoldingStartIncluded(bool included) { m_foldingStartIncluded = included; }
+ bool foldingStartIncluded() const { return m_foldingStartIncluded; }
+ void setFoldingEndIncluded(bool included) { m_foldingEndIncluded = included; }
+ bool foldingEndIncluded() const { return m_foldingEndIncluded; }
+
private:
TextMarks m_marks;
- uint m_collapseIncludesClosure : 1;
- uint m_collapseMode : 4;
- uint m_closingCollapseMode : 4;
- uint m_collapsed : 1;
+ uint m_folded : 1;
uint m_ifdefedOut : 1;
+ uint m_foldingIndent : 16;
+ uint m_foldingStartIncluded : 1;
+ uint m_foldingEndIncluded : 1;
Parentheses m_parentheses;
};
static int braceDepth(const QTextBlock &block);
static void setBraceDepth(QTextBlock &block, int depth);
static void changeBraceDepth(QTextBlock &block, int delta);
+ static void setFoldingIndent(const QTextBlock &block, int indent);
+ static int foldingIndent(const QTextBlock &block);
+ static void changeFoldingIndent(QTextBlock &block, int delta);
+ static bool canFold(const QTextBlock &block);
+ static void doFoldOrUnfold(const QTextBlock& block, bool unfold);
+ static bool isFolded(const QTextBlock &block);
+ static void setFolded(const QTextBlock &block, bool folded);
static TextBlockUserData *testUserData(const QTextBlock &block) {
return static_cast<TextBlockUserData*>(block.userData());
viewport()->setMouseTracking(true);
d->extraAreaSelectionAnchorBlockNumber
= d->extraAreaToggleMarkBlockNumber
- = d->extraAreaHighlightCollapseBlockNumber
- = d->extraAreaHighlightCollapseColumn
+ = d->extraAreaHighlightFoldedBlockNumber
= -1;
- d->visibleCollapsedBlockNumber = d->suggestedVisibleCollapsedBlockNumber = -1;
+ d->visibleFoldedBlockNumber = d->suggestedVisibleFoldedBlockNumber = -1;
connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(slotUpdateExtraAreaWidth()));
connect(this, SIGNAL(modificationChanged(bool)), this, SLOT(slotModificationChanged(bool)));
delete dlg;
}
-static int collapseBoxWidth(const QFontMetrics &fm)
+static int foldBoxWidth(const QFontMetrics &fm)
{
const int lineSpacing = fm.lineSpacing();
return lineSpacing + lineSpacing%2 + 1;
/*
Collapses the first comment in a file, if there is only whitespace above
*/
-void BaseTextEditorPrivate::collapseLicenseHeader()
+void BaseTextEditorPrivate::foldLicenseHeader()
{
QTextDocument *doc = q->document();
BaseTextDocumentLayout *documentLayout = qobject_cast<BaseTextDocumentLayout*>(doc->documentLayout());
QTextBlock block = doc->firstBlock();
const TabSettings &ts = m_document->tabSettings();
while (block.isValid() && block.isVisible()) {
- TextBlockUserData *data = TextBlockUserData::canCollapse(block);
- if (data && block.next().isVisible()) {
- QChar character;
- static_cast<TextBlockUserData*>(data)->collapseAtPos(&character);
- if (character != QLatin1Char('+'))
- break; // not a comment
- TextBlockUserData::doCollapse(block, false);
- moveCursorVisible();
- documentLayout->requestUpdate();
- documentLayout->emitDocumentSizeChanged();
- break;
- }
QString text = block.text();
+ if (BaseTextDocumentLayout::canFold(block) && block.next().isVisible()) {
+ if (text.trimmed().startsWith(QLatin1String("/*"))) {
+ BaseTextDocumentLayout::doFoldOrUnfold(block, false);
+ moveCursorVisible();
+ documentLayout->requestUpdate();
+ documentLayout->emitDocumentSizeChanged();
+ break;
+ }
+ }
if (ts.firstNonSpace(text) < text.size())
break;
block = block.next();
setTextCursor(cursor);
}
+void BaseTextEditor::insertLineAbove()
+{
+ QTextCursor cursor = textCursor();
+ cursor.beginEditBlock();
+ cursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::MoveAnchor);
+ cursor.insertBlock();
+ indent(document(), cursor, QChar::Null);
+ cursor.endEditBlock();
+ setTextCursor(cursor);
+}
+
+void BaseTextEditor::insertLineBelow()
+{
+ QTextCursor cursor = textCursor();
+ cursor.beginEditBlock();
+ cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::MoveAnchor);
+ cursor.insertBlock();
+ indent(document(), cursor, QChar::Null);
+ cursor.endEditBlock();
+ setTextCursor(cursor);
+}
+
void BaseTextEditor::moveLineUp()
{
moveLineUpDown(true);
QTextCursor cursor = textCursor();
QTextCursor move = cursor;
- move.setVisualNavigation(false); // this opens collapsed items instead of destroying them
+ move.setVisualNavigation(false); // this opens folded items instead of destroying them
if (d->m_moveLineUndoHack)
move.joinPreviousEditBlock();
QToolTip::hideText();
d->m_moveLineUndoHack = false;
- d->clearVisibleCollapsedBlock();
+ d->clearVisibleFoldedBlock();
QKeyEvent *original_e = e;
d->m_lastEventWasBlockSelectionEvent = false;
stream << column;
// store code folding state
- QList<int> collapsedBlocks;
+ QList<int> foldedBlocks;
QTextBlock block = document()->firstBlock();
while (block.isValid()) {
- if (block.userData() && static_cast<TextBlockUserData*>(block.userData())->collapsed()) {
+ if (block.userData() && static_cast<TextBlockUserData*>(block.userData())->folded()) {
int number = block.blockNumber();
- if (static_cast<TextBlockUserData*>(block.userData())->collapseMode()
- == TextBlockUserData::CollapseThis)
- number--;
- collapsedBlocks += number;
+ foldedBlocks += number;
}
block = block.next();
}
- stream << collapsedBlocks;
+ stream << foldedBlocks;
return state;
}
{
if (state.isEmpty()) {
if (d->m_displaySettings.m_autoFoldFirstComment)
- d->collapseLicenseHeader();
+ d->foldLicenseHeader();
return false;
}
int version;
foreach(int blockNumber, collapsedBlocks) {
QTextBlock block = doc->findBlockByNumber(qMax(0, blockNumber));
if (block.isValid())
- TextBlockUserData::doCollapse(block, false);
+ BaseTextDocumentLayout::doFoldOrUnfold(block, false);
}
} else {
if (d->m_displaySettings.m_autoFoldFirstComment)
- d->collapseLicenseHeader();
+ d->foldLicenseHeader();
}
d->m_lastCursorChangeWasInteresting = false; // avoid adding last position to history
BaseTextEditorPrivate::BaseTextEditorPrivate()
:
+ m_lastScrollPos(-1),
+ m_lineNumber(-1),
+ q(0),
m_contentsChanged(false),
m_lastCursorChangeWasInteresting(false),
m_allowSkippingOfBlockEnd(false),
m_document(new BaseTextDocument),
m_parenthesesMatchingEnabled(false),
m_autoParenthesesEnabled(true),
+ m_updateTimer(0),
+ m_formatRange(false),
+ m_parenthesesMatchingTimer(0),
m_extraArea(0),
- m_mouseOnCollapsedMarker(false),
+ extraAreaSelectionAnchorBlockNumber(-1),
+ extraAreaToggleMarkBlockNumber(-1),
+ extraAreaHighlightFoldedBlockNumber(-1),
+ m_overlay(0),
+ m_snippetOverlay(0),
+ m_searchResultOverlay(0),
+ visibleFoldedBlockNumber(-1),
+ suggestedVisibleFoldedBlockNumber(-1),
+ m_mouseOnFoldedMarker(false),
m_marksVisible(false),
m_codeFoldingVisible(false),
m_codeFoldingSupported(false),
m_lineSeparatorsAllowed(false),
m_visibleWrapColumn(0),
m_linkPressed(false),
+ m_delayedUpdateTimer(0),
m_editable(0),
m_actionHack(0),
m_inBlockSelectionMode(false),
m_lastEventWasBlockSelectionEvent(false),
- m_blockSelectionExtraX(0),
+ m_blockSelectionExtraX(-1),
m_moveLineUndoHack(false),
- m_cursorBlockNumber(-1)
+ m_findScopeVerticalBlockSelection(0),
+ m_highlightBlocksTimer(0),
+ m_cursorBlockNumber(-1),
+ m_inKeyPressEvent(false)
{
}
QRect(cr.left(), cr.top(), extraAreaWidth(), cr.height())));
}
-QRect BaseTextEditor::collapseBox()
+QRect BaseTextEditor::foldBox()
{
- if (d->m_highlightBlocksInfo.isEmpty() || d->extraAreaHighlightCollapseBlockNumber < 0)
+ if (d->m_highlightBlocksInfo.isEmpty() || d->extraAreaHighlightFoldedBlockNumber < 0)
return QRect();
QTextBlock begin = document()->findBlockByNumber(d->m_highlightBlocksInfo.open.last());
- if (TextBlockUserData::hasCollapseAfter(begin.previous()))
- begin = begin.previous();
-
QTextBlock end = document()->findBlockByNumber(d->m_highlightBlocksInfo.close.first());
if (!begin.isValid() || !end.isValid())
return QRect();
QRectF br = blockBoundingGeometry(begin).translated(contentOffset());
QRectF er = blockBoundingGeometry(end).translated(contentOffset());
- return QRect(d->m_extraArea->width() - collapseBoxWidth(fontMetrics()),
+ return QRect(d->m_extraArea->width() - foldBoxWidth(fontMetrics()),
int(br.top()),
- collapseBoxWidth(fontMetrics()),
+ foldBoxWidth(fontMetrics()),
er.bottom() - br.top());
}
-QTextBlock BaseTextEditor::collapsedBlockAt(const QPoint &pos, QRect *box) const
+QTextBlock BaseTextEditor::foldedBlockAt(const QPoint &pos, QRect *box) const
{
QPointF offset(contentOffset());
QTextBlock block = firstVisibleBlock();
for (int i = 0; i <= depth; ++i) {
int vi = i > 0 ? d->m_highlightBlocksInfo.visualIndent.at(i-1) : 0;
painter.fillRect(rr.adjusted(vi, 0, -8*i, 0), calcBlendColor(baseColor, i, count));
- if (d->m_highlightCurrentLine && blockFP == textCursorBlock) {
- QRectF rrr = blockFP.layout()->lineForTextPosition(textCursor().positionInBlock()).rect();
- rrr.moveTop(rrr.top() + rr.top());
- rrr.setLeft(rr.left());
- rrr.setRight(rr.right());
- painter.fillRect(rrr.adjusted(vi, 0, -8*i, 0),
- calcBlendColor(d->m_currentLineFormat.background().color(), i, count));
- }
}
}
offsetFP.ry() += r.height();
rr.moveTop(rr.top() + r.top());
rr.setLeft(0);
rr.setRight(viewportRect.width() - offset.x());
- if (lineX > 0) {
- if (lineX < rr.right()) {
- QRectF rrr = rr;
- rrr.setLeft(lineX);
- painter.fillRect(rrr,
- blendColors(
- d->m_currentLineFormat.background().color(),
- d->m_ifdefedOutFormat.background().color(),
- 50)
- );
- const QColor col = (palette().base().color().value() > 128) ? Qt::black : Qt::white;
- const QPen pen = painter.pen();
- painter.setPen(blendColors(d->m_currentLineFormat.background().color(), col, 32));
- painter.drawLine(QPointF(lineX, rr.top()), QPointF(lineX, rr.bottom()));
- painter.setPen(pen);
- }
- rr.setRight(qMin(lineX, rr.right()));
- }
- if (d->m_highlightBlocksInfo.isEmpty() || BaseTextDocumentLayout::ifdefedOut(block))
- painter.fillRect(rr, d->m_currentLineFormat.background());
+ QColor color = d->m_currentLineFormat.background().color();
+ // set alpha, otherwise we cannot see block highlighting and find scope underneath
+ color.setAlpha(128);
+ painter.fillRect(rr, color);
}
bool drawCursor = ((editable || true) // we want the cursor in read-only mode
block = block.next();
if (!block.isVisible()) {
- if (block.blockNumber() == d->visibleCollapsedBlockNumber) {
+ if (block.blockNumber() == d->visibleFoldedBlockNumber) {
visibleCollapsedBlock = block;
visibleCollapsedBlockOffset = offset + QPointF(0,1);
}
QString replacement = QLatin1String("...");
- QTextBlock info = block;
- if (block.userData()
- && static_cast<TextBlockUserData*>(block.userData())->collapseMode() == TextBlockUserData::CollapseAfter)
- ;
- else if (block.next().userData()
- && static_cast<TextBlockUserData*>(block.next().userData())->collapseMode()
- == TextBlockUserData::CollapseThis) {
- replacement.prepend(nextBlock.text().trimmed().left(1));
- info = nextBlock;
+ if (TextBlockUserData *nextBlockUserData = BaseTextDocumentLayout::testUserData(nextBlock)) {
+ if (nextBlockUserData->foldingStartIncluded())
+ replacement.prepend(nextBlock.text().trimmed().left(1));
}
-
block = nextVisibleBlock.previous();
if (!block.isValid())
block = doc->lastBlock();
- if (info.userData()
- && static_cast<TextBlockUserData*>(info.userData())->collapseIncludesClosure()) {
- QString right = block.text().trimmed();
- if (right.endsWith(QLatin1Char(';'))) {
- right.chop(1);
- right = right.trimmed();
- replacement.append(right.right(right.endsWith(QLatin1Char('/')) ? 2 : 1));
- replacement.append(QLatin1Char(';'));
- } else {
- replacement.append(right.right(right.endsWith(QLatin1Char('/')) ? 2 : 1));
+ if (TextBlockUserData *blockUserData = BaseTextDocumentLayout::testUserData(block)) {
+ if (blockUserData->foldingEndIncluded()) {
+ QString right = block.text().trimmed();
+ if (right.endsWith(QLatin1Char(';'))) {
+ right.chop(1);
+ right = right.trimmed();
+ replacement.append(right.right(right.endsWith(QLatin1Char('/')) ? 2 : 1));
+ replacement.append(QLatin1Char(';'));
+ } else {
+ replacement.append(right.right(right.endsWith(QLatin1Char('/')) ? 2 : 1));
+ }
}
}
+
if (selectThis)
painter.setPen(palette().highlightedText().color());
painter.drawText(collapseRect, Qt::AlignCenter, replacement);
space += 4;
if (d->m_codeFoldingVisible)
- space += collapseBoxWidth(fm);
+ space += foldBoxWidth(fm);
return space;
}
if (d->m_marksVisible)
markWidth += fm.lineSpacing();
- const int collapseColumnWidth = d->m_codeFoldingVisible ? collapseBoxWidth(fm): 0;
+ const int collapseColumnWidth = d->m_codeFoldingVisible ? foldBoxWidth(fm): 0;
const int extraAreaWidth = d->m_extraArea->width() - collapseColumnWidth;
painter.fillRect(e->rect(), pal.color(QPalette::Base));
if (d->m_codeFoldingVisible) {
- bool collapseThis = false;
- bool collapseAfter = false;
- bool hasClosingCollapse = false;
-
- if (TextBlockUserData *userData = static_cast<TextBlockUserData*>(block.userData())) {
- if (!userData->ifdefedOut()) {
- collapseAfter = (userData->collapseMode() == TextBlockUserData::CollapseAfter);
- collapseThis = (userData->collapseMode() == TextBlockUserData::CollapseThis);
- hasClosingCollapse = userData->hasClosingCollapse() && (previousBraceDepth > 0);
- }
- }
-
- int extraAreaHighlightCollapseBlockNumber = -1;
- int extraAreaHighlightCollapseEndBlockNumber = -1;
+ int extraAreaHighlightFoldBlockNumber = -1;
+ int extraAreaHighlightFoldEndBlockNumber = -1;
bool endIsVisible = false;
if (!d->m_highlightBlocksInfo.isEmpty()) {
- extraAreaHighlightCollapseBlockNumber = d->m_highlightBlocksInfo.open.last();
- extraAreaHighlightCollapseEndBlockNumber = d->m_highlightBlocksInfo.close.first();
- endIsVisible = doc->findBlockByNumber(extraAreaHighlightCollapseEndBlockNumber).isVisible();
-
- QTextBlock before = doc->findBlockByNumber(extraAreaHighlightCollapseBlockNumber-1);
- if (TextBlockUserData::hasCollapseAfter(before)) {
- extraAreaHighlightCollapseBlockNumber--;
- }
+ extraAreaHighlightFoldBlockNumber = d->m_highlightBlocksInfo.open.last();
+ extraAreaHighlightFoldEndBlockNumber = d->m_highlightBlocksInfo.close.first();
+ endIsVisible = doc->findBlockByNumber(extraAreaHighlightFoldEndBlockNumber).isVisible();
+
+// QTextBlock before = doc->findBlockByNumber(extraAreaHighlightCollapseBlockNumber-1);
+// if (TextBlockUserData::hasCollapseAfter(before)) {
+// extraAreaHighlightCollapseBlockNumber--;
+// }
}
TextBlockUserData *nextBlockUserData = BaseTextDocumentLayout::testUserData(nextBlock);
- bool collapseNext = nextBlockUserData
- && nextBlockUserData->collapseMode() == TextBlockUserData::CollapseThis
- && !nextBlockUserData->ifdefedOut();
+ bool drawBox = nextBlockUserData
+ && BaseTextDocumentLayout::foldingIndent(block) < nextBlockUserData->foldingIndent();
+
- bool nextHasClosingCollapse = nextBlockUserData
- && nextBlockUserData->hasClosingCollapseInside()
- && nextBlockUserData->ifdefedOut();
- bool drawBox = ((collapseAfter || collapseNext) && !nextHasClosingCollapse);
- bool active = blockNumber == extraAreaHighlightCollapseBlockNumber;
- bool drawStart = drawBox && active;
- bool drawEnd = blockNumber == extraAreaHighlightCollapseEndBlockNumber || (drawStart && !endIsVisible);
- bool hovered = blockNumber >= extraAreaHighlightCollapseBlockNumber
- && blockNumber <= extraAreaHighlightCollapseEndBlockNumber;
+ bool active = blockNumber == extraAreaHighlightFoldBlockNumber;
- int boxWidth = collapseBoxWidth(fm);
+ bool drawStart = active;
+ bool drawEnd = blockNumber == extraAreaHighlightFoldEndBlockNumber || (drawStart && !endIsVisible);
+ bool hovered = blockNumber >= extraAreaHighlightFoldBlockNumber
+ && blockNumber <= extraAreaHighlightFoldEndBlockNumber;
+
+ int boxWidth = foldBoxWidth(fm);
if (hovered) {
int itop = qRound(top);
int ibottom = qRound(bottom);
{
#if 0
qDebug() << "block" << textCursor().blockNumber()+1
- << "depth:" << BaseTextDocumentLayout::braceDepth(textCursor().block())
- << '/' << BaseTextDocumentLayout::braceDepth(document()->lastBlock());
+ << "brace depth:" << BaseTextDocumentLayout::braceDepth(textCursor().block())
+ << "indent:" << BaseTextDocumentLayout::userData(textCursor().block())->foldingIndent();
#endif
if (!d->m_contentsChanged && d->m_lastCursorChangeWasInteresting) {
Core::EditorManager::instance()->addCurrentPositionToNavigationHistory(editableInterface(), d->m_tempNavigationState);
if (d->m_displaySettings.m_highlightBlocks) {
QTextCursor cursor = textCursor();
- d->extraAreaHighlightCollapseBlockNumber = cursor.blockNumber();
- d->extraAreaHighlightCollapseColumn = cursor.position() - cursor.block().position();
+ d->extraAreaHighlightFoldedBlockNumber = cursor.blockNumber();
d->m_highlightBlocksTimer->start(100);
}
}
/* The syntax highlighting state changes. This opens up for
the possibility that the paragraph has braces that support
code folding. In this case, do the save thing and also
- update the previous block, which might contain a collapse
+ update the previous block, which might contain a fold
box which now is invalid.*/
emit requestBlockUpdate(block.previous());
}
int timeout = 4900 / (delta * delta);
d->autoScrollTimer.start(timeout, this);
- } else if (e->timerId() == d->collapsedBlockTimer.timerId()) {
- d->visibleCollapsedBlockNumber = d->suggestedVisibleCollapsedBlockNumber;
- d->suggestedVisibleCollapsedBlockNumber = -1;
- d->collapsedBlockTimer.stop();
+ } else if (e->timerId() == d->foldedBlockTimer.timerId()) {
+ d->visibleFoldedBlockNumber = d->suggestedVisibleFoldedBlockNumber;
+ d->suggestedVisibleFoldedBlockNumber = -1;
+ d->foldedBlockTimer.stop();
viewport()->update();
}
QPlainTextEdit::timerEvent(e);
}
-void BaseTextEditorPrivate::clearVisibleCollapsedBlock()
+void BaseTextEditorPrivate::clearVisibleFoldedBlock()
{
- if (suggestedVisibleCollapsedBlockNumber) {
- suggestedVisibleCollapsedBlockNumber = -1;
- collapsedBlockTimer.stop();
+ if (suggestedVisibleFoldedBlockNumber) {
+ suggestedVisibleFoldedBlockNumber = -1;
+ foldedBlockTimer.stop();
}
- if (visibleCollapsedBlockNumber >= 0) {
- visibleCollapsedBlockNumber = -1;
+ if (visibleFoldedBlockNumber >= 0) {
+ visibleFoldedBlockNumber = -1;
q->viewport()->update();
}
}
updateLink(e);
if (e->buttons() == Qt::NoButton) {
- const QTextBlock collapsedBlock = collapsedBlockAt(e->pos());
+ const QTextBlock collapsedBlock = foldedBlockAt(e->pos());
const int blockNumber = collapsedBlock.next().blockNumber();
if (blockNumber < 0) {
- d->clearVisibleCollapsedBlock();
- } else if (blockNumber != d->visibleCollapsedBlockNumber) {
- d->suggestedVisibleCollapsedBlockNumber = blockNumber;
- d->collapsedBlockTimer.start(40, this);
+ d->clearVisibleFoldedBlock();
+ } else if (blockNumber != d->visibleFoldedBlockNumber) {
+ d->suggestedVisibleFoldedBlockNumber = blockNumber;
+ d->foldedBlockTimer.start(40, this);
}
// Update the mouse cursor
- if (collapsedBlock.isValid() && !d->m_mouseOnCollapsedMarker) {
- d->m_mouseOnCollapsedMarker = true;
+ if (collapsedBlock.isValid() && !d->m_mouseOnFoldedMarker) {
+ d->m_mouseOnFoldedMarker = true;
viewport()->setCursor(Qt::PointingHandCursor);
- } else if (!collapsedBlock.isValid() && d->m_mouseOnCollapsedMarker) {
- d->m_mouseOnCollapsedMarker = false;
+ } else if (!collapsedBlock.isValid() && d->m_mouseOnFoldedMarker) {
+ d->m_mouseOnFoldedMarker = false;
viewport()->setCursor(Qt::IBeamCursor);
}
} else {
if (e->button() == Qt::LeftButton) {
d->clearBlockSelection(); // just in case, otherwise we might get strange drag and drop
- QTextBlock collapsedBlock = collapsedBlockAt(e->pos());
- if (collapsedBlock.isValid()) {
- toggleBlockVisible(collapsedBlock);
+ QTextBlock foldedBlock = foldedBlockAt(e->pos());
+ if (foldedBlock.isValid()) {
+ toggleBlockVisible(foldedBlock);
viewport()->setCursor(Qt::IBeamCursor);
}
void BaseTextEditor::extraAreaMouseEvent(QMouseEvent *e)
{
QTextCursor cursor = cursorForPosition(QPoint(0, e->pos().y()));
- cursor.setPosition(cursor.block().position());
int markWidth;
extraAreaWidth(&markWidth);
if (d->m_codeFoldingVisible
&& e->type() == QEvent::MouseMove && e->buttons() == 0) { // mouse tracking
// Update which folder marker is highlighted
- const int highlightBlockNumber = d->extraAreaHighlightCollapseBlockNumber;
- const int highlightColumn = d->extraAreaHighlightCollapseColumn;
- d->extraAreaHighlightCollapseBlockNumber = -1;
- d->extraAreaHighlightCollapseColumn = -1;
-
- if (e->pos().x() > extraArea()->width() - collapseBoxWidth(fontMetrics())) {
- d->extraAreaHighlightCollapseBlockNumber = cursor.blockNumber();
- if (TextBlockUserData::canCollapse(cursor.block())
- || !TextBlockUserData::hasClosingCollapse(cursor.block()))
- d->extraAreaHighlightCollapseColumn = cursor.block().length()-1;
- if (TextBlockUserData::hasCollapseAfter(cursor.block())) {
- d->extraAreaHighlightCollapseBlockNumber++;
- d->extraAreaHighlightCollapseColumn = -1;
- if (TextBlockUserData::canCollapse(cursor.block().next())
- || !TextBlockUserData::hasClosingCollapse(cursor.block().next()))
- d->extraAreaHighlightCollapseColumn = cursor.block().next().length()-1;
- }
+ const int highlightBlockNumber = d->extraAreaHighlightFoldedBlockNumber;
+ d->extraAreaHighlightFoldedBlockNumber = -1;
+
+ if (e->pos().x() > extraArea()->width() - foldBoxWidth(fontMetrics())) {
+ d->extraAreaHighlightFoldedBlockNumber = cursor.blockNumber();
} else if (d->m_displaySettings.m_highlightBlocks) {
QTextCursor cursor = textCursor();
- d->extraAreaHighlightCollapseBlockNumber = cursor.blockNumber();
- d->extraAreaHighlightCollapseColumn = cursor.position() - cursor.block().position();
+ d->extraAreaHighlightFoldedBlockNumber = cursor.blockNumber();
}
- if (highlightBlockNumber != d->extraAreaHighlightCollapseBlockNumber
- || highlightColumn != d->extraAreaHighlightCollapseColumn) {
+ if (highlightBlockNumber != d->extraAreaHighlightFoldedBlockNumber)
d->m_highlightBlocksTimer->start(d->m_highlightBlocksInfo.isEmpty() ? 120 : 0);
}
- }
// Set whether the mouse cursor is a hand or normal arrow
if (e->type() == QEvent::MouseMove) {
if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonDblClick) {
if (e->button() == Qt::LeftButton) {
- int boxWidth = collapseBoxWidth(fontMetrics());
+ int boxWidth = foldBoxWidth(fontMetrics());
if (d->m_codeFoldingVisible && e->pos().x() > extraArea()->width() - boxWidth) {
if (!cursor.block().next().isVisible()) {
toggleBlockVisible(cursor.block());
d->moveCursorVisible(false);
- } else if (collapseBox().contains(e->pos())) {
+ } else if (foldBox().contains(e->pos())) {
cursor.setPosition(
document()->findBlockByNumber(d->m_highlightBlocksInfo.open.last()).position()
);
QTextBlock c = cursor.block();
- if (TextBlockUserData::hasCollapseAfter(c.previous()))
- c = c.previous();
toggleBlockVisible(c);
d->moveCursorVisible(false);
}
QTC_ASSERT(documentLayout, return);
bool visible = block.next().isVisible();
- TextBlockUserData::doCollapse(block, !visible);
+ BaseTextDocumentLayout::doFoldOrUnfold(block, !visible);
documentLayout->requestUpdate();
documentLayout->emitDocumentSizeChanged();
}
void BaseTextEditor::wheelEvent(QWheelEvent *e)
{
- d->clearVisibleCollapsedBlock();
+ d->clearVisibleFoldedBlock();
if (scrollWheelZoomingEnabled() && e->modifiers() & Qt::ControlModifier) {
const int delta = e->delta();
if (delta < 0)
void BaseTextEditor::zoomIn(int range)
{
- d->clearVisibleCollapsedBlock();
+ d->clearVisibleFoldedBlock();
emit requestFontZoom(range*10);
}
{
BaseTextEditorPrivateHighlightBlocks highlightBlocksInfo;
- if (d->extraAreaHighlightCollapseBlockNumber >= 0) {
- QTextBlock block = document()->findBlockByNumber(d->extraAreaHighlightCollapseBlockNumber);
- if (block.isValid()) {
- QTextCursor cursor(block);
- if (d->extraAreaHighlightCollapseColumn >= 0)
- cursor.setPosition(cursor.position() + qMin(d->extraAreaHighlightCollapseColumn,
- block.length()-1));
- QTextCursor closeCursor;
- bool firstRun = true;
- while (TextBlockUserData::findPreviousBlockOpenParenthesis(&cursor, firstRun)) {
- firstRun = false;
- highlightBlocksInfo.open.prepend(cursor.blockNumber());
- int visualIndent = d->visualIndent(cursor.block());
- if (closeCursor.isNull())
- closeCursor = cursor;
- if (TextBlockUserData::findNextBlockClosingParenthesis(&closeCursor)) {
- highlightBlocksInfo.close.append(closeCursor.blockNumber());
- visualIndent = qMin(visualIndent, d->visualIndent(closeCursor.block()));
- }
- highlightBlocksInfo.visualIndent.prepend(visualIndent);
+ QTextBlock block;
+ if (d->extraAreaHighlightFoldedBlockNumber >= 0) {
+ block = document()->findBlockByNumber(d->extraAreaHighlightFoldedBlockNumber);
+ if (block.isValid()
+ && block.next().isValid()
+ && BaseTextDocumentLayout::foldingIndent(block.next())
+ > BaseTextDocumentLayout::foldingIndent(block))
+ block = block.next();
+ }
+
+ QTextBlock closeBlock = block;
+ while (block.isValid()) {
+ int foldingIndent = BaseTextDocumentLayout::foldingIndent(block);
+
+ while (block.previous().isValid() && BaseTextDocumentLayout::foldingIndent(block) >= foldingIndent)
+ block = block.previous();
+ int nextIndent = BaseTextDocumentLayout::foldingIndent(block);
+ if (nextIndent == foldingIndent)
+ break;
+ highlightBlocksInfo.open.prepend(block.blockNumber());
+ while (closeBlock.next().isValid()
+ && BaseTextDocumentLayout::foldingIndent(closeBlock.next()) >= foldingIndent )
+ closeBlock = closeBlock.next();
+ highlightBlocksInfo.close.append(closeBlock.blockNumber());
+ int visualIndent = qMin(d->visualIndent(block), d->visualIndent(closeBlock));
+ highlightBlocksInfo.visualIndent.prepend(visualIndent);
+ }
+
+#if 0
+ if (block.isValid()) {
+ QTextCursor cursor(block);
+ if (d->extraAreaHighlightCollapseColumn >= 0)
+ cursor.setPosition(cursor.position() + qMin(d->extraAreaHighlightCollapseColumn,
+ block.length()-1));
+ QTextCursor closeCursor;
+ bool firstRun = true;
+ while (TextBlockUserData::findPreviousBlockOpenParenthesis(&cursor, firstRun)) {
+ firstRun = false;
+ highlightBlocksInfo.open.prepend(cursor.blockNumber());
+ int visualIndent = d->visualIndent(cursor.block());
+ if (closeCursor.isNull())
+ closeCursor = cursor;
+ if (TextBlockUserData::findNextBlockClosingParenthesis(&closeCursor)) {
+ highlightBlocksInfo.close.append(closeCursor.blockNumber());
+ visualIndent = qMin(visualIndent, d->visualIndent(closeCursor.block()));
}
+ highlightBlocksInfo.visualIndent.prepend(visualIndent);
}
}
-
+#endif
if (d->m_highlightBlocksInfo != highlightBlocksInfo) {
d->m_highlightBlocksInfo = highlightBlocksInfo;
viewport()->update();
braceDepthDelta -= delta;
}
- if (braceDepthDelta)
+ if (braceDepthDelta) {
BaseTextDocumentLayout::changeBraceDepth(block,braceDepthDelta);
+ BaseTextDocumentLayout::changeFoldingIndent(block, braceDepthDelta); // ### C++ only, refactor!
+ }
block = block.next();
}
d->m_displaySettings = ds;
if (!ds.m_highlightBlocks) {
- d->extraAreaHighlightCollapseBlockNumber = d->extraAreaHighlightCollapseColumn = -1;
+ d->extraAreaHighlightFoldedBlockNumber = -1;
d->m_highlightBlocksInfo = BaseTextEditorPrivateHighlightBlocks();
}
setAutoParenthesesEnabled(completionSettings.m_autoInsertBrackets);
}
-void BaseTextEditor::collapse()
+void BaseTextEditor::fold()
{
QTextDocument *doc = document();
BaseTextDocumentLayout *documentLayout = qobject_cast<BaseTextDocumentLayout*>(doc->documentLayout());
QTC_ASSERT(documentLayout, return);
QTextBlock block = textCursor().block();
- QTextBlock curBlock = block;
- while (block.isValid()) {
- if (TextBlockUserData::canCollapse(block) && block.next().isVisible()) {
- if (block == curBlock || block.next() == curBlock)
- break;
- if ((block.next().userState()) >> 8 <= (curBlock.previous().userState() >> 8))
- break;
- }
- block = block.previous();
+ if (!(BaseTextDocumentLayout::canFold(block) && block.next().isVisible())) {
+ // find the closest previous block which can fold
+ int indent = BaseTextDocumentLayout::foldingIndent(block);
+ while (block.isValid() && (BaseTextDocumentLayout::foldingIndent(block) >= indent || !block.isVisible()))
+ block = block.previous();
}
if (block.isValid()) {
- TextBlockUserData::doCollapse(block, false);
+ BaseTextDocumentLayout::doFoldOrUnfold(block, false);
d->moveCursorVisible();
documentLayout->requestUpdate();
documentLayout->emitDocumentSizeChanged();
}
}
-void BaseTextEditor::expand()
+void BaseTextEditor::unfold()
{
QTextDocument *doc = document();
BaseTextDocumentLayout *documentLayout = qobject_cast<BaseTextDocumentLayout*>(doc->documentLayout());
QTextBlock block = textCursor().block();
while (block.isValid() && !block.isVisible())
block = block.previous();
- TextBlockUserData::doCollapse(block, true);
+ BaseTextDocumentLayout::doFoldOrUnfold(block, true);
d->moveCursorVisible();
documentLayout->requestUpdate();
documentLayout->emitDocumentSizeChanged();
}
-void BaseTextEditor::unCollapseAll()
+void BaseTextEditor::unfoldAll()
{
QTextDocument *doc = document();
BaseTextDocumentLayout *documentLayout = qobject_cast<BaseTextDocumentLayout*>(doc->documentLayout());
QTextBlock block = doc->firstBlock();
bool makeVisible = true;
while (block.isValid()) {
- if (block.isVisible() && TextBlockUserData::canCollapse(block) && block.next().isVisible()) {
+ if (block.isVisible() && BaseTextDocumentLayout::canFold(block) && block.next().isVisible()) {
makeVisible = false;
break;
}
block = doc->firstBlock();
while (block.isValid()) {
- if (TextBlockUserData::canCollapse(block))
- TextBlockUserData::doCollapse(block, makeVisible);
+ if (BaseTextDocumentLayout::canFold(block))
+ BaseTextDocumentLayout::doFoldOrUnfold(block, makeVisible);
block = block.next();
}
void cutLine();
void deleteLine();
- void unCollapseAll();
- void collapse();
- void expand();
+ void unfoldAll();
+ void fold();
+ void unfold();
void selectEncoding();
void gotoBlockStart();
void joinLines();
+ void insertLineAbove();
+ void insertLineBelow();
+
void cleanWhitespace();
signals:
ParenthesesMatchingSelection,
CodeWarningsSelection,
CodeSemanticsSelection,
+ UndefinedSymbolSelection,
UnusedSymbolSelection,
FakeVimSelection,
OtherSelection,
SnippetPlaceholderSelection,
+ TypeSelection,
NExtraSelectionKinds
};
void setExtraSelections(ExtraSelectionKind kind, const QList<QTextEdit::ExtraSelection> &selections);
void indentInsertedText(const QTextCursor &tc);
-protected:
// Returns the text to complete at the cursor position, or an empty string
virtual QString autoComplete(QTextCursor &cursor, const QString &text) const;
// Handles backspace. When returning true, backspace processing is stopped
// Returns the text that needs to be inserted
virtual QString insertParagraphSeparator(const QTextCursor &tc) const;
+protected:
static void countBracket(QChar open, QChar close, QChar c, int *errors, int *stillopen);
static void countBrackets(QTextCursor cursor, int from, int end, QChar open, QChar close,
const QRect &clip);
void toggleBlockVisible(const QTextBlock &block);
- QRect collapseBox();
+ QRect foldBox();
- QTextBlock collapsedBlockAt(const QPoint &pos, QRect *box = 0) const;
+ QTextBlock foldedBlockAt(const QPoint &pos, QRect *box = 0) const;
void updateLink(QMouseEvent *e);
void showLink(const Link &);
int extraAreaSelectionAnchorBlockNumber;
int extraAreaToggleMarkBlockNumber;
- int extraAreaHighlightCollapseBlockNumber;
- int extraAreaHighlightCollapseColumn;
+ int extraAreaHighlightFoldedBlockNumber;
TextEditorOverlay *m_overlay;
TextEditorOverlay *m_snippetOverlay;
QTextCharFormat m_occurrencesFormat;
QTextCharFormat m_occurrenceRenameFormat;
- QBasicTimer collapsedBlockTimer;
- int visibleCollapsedBlockNumber;
- int suggestedVisibleCollapsedBlockNumber;
- void clearVisibleCollapsedBlock();
- bool m_mouseOnCollapsedMarker;
- void collapseLicenseHeader();
+ QBasicTimer foldedBlockTimer;
+ int visibleFoldedBlockNumber;
+ int suggestedVisibleFoldedBlockNumber;
+ void clearVisibleFoldedBlock();
+ bool m_mouseOnFoldedMarker;
+ void foldLicenseHeader();
QBasicTimer autoScrollTimer;
void updateMarksLineNumber();
QColor background = m_scheme->formatFor(description.id()).background();
if (background.isValid())
return background;
+ else
+ break;
}
case Qt::FontRole: {
QFont font = m_baseFont;
if (!settingsFound) { // Apply defaults
foreach (const FormatDescription &f, m_descriptions) {
- const QString id = f.id();
+ const QString fid = f.id();
- m_value.formatFor(id).setForeground(f.foreground());
- m_value.formatFor(id).setBackground(f.background());
- m_value.formatFor(id).setBold(f.format().bold());
- m_value.formatFor(id).setItalic(f.format().italic());
+ m_value.formatFor(fid).setForeground(f.foreground());
+ m_value.formatFor(fid).setBackground(f.background());
+ m_value.formatFor(fid).setBold(f.format().bold());
+ m_value.formatFor(fid).setItalic(f.format().italic());
}
} else if (m_value.colorSchemeFileName().isEmpty()) {
// No color scheme was loaded, but one might be imported from the ini file
ColorScheme defaultScheme;
foreach (const FormatDescription &f, m_descriptions) {
- const QString id = f.id();
- defaultScheme.formatFor(id).setForeground(f.foreground());
- defaultScheme.formatFor(id).setBackground(f.background());
- defaultScheme.formatFor(id).setBold(f.format().bold());
- defaultScheme.formatFor(id).setItalic(f.format().italic());
+ const QString fid = f.id();
+ defaultScheme.formatFor(fid).setForeground(f.foreground());
+ defaultScheme.formatFor(fid).setBackground(f.background());
+ defaultScheme.formatFor(fid).setBold(f.format().bold());
+ defaultScheme.formatFor(fid).setItalic(f.format().italic());
}
if (m_value.colorScheme() != defaultScheme) {
// Save it as a color scheme file
qreal smallRatio;
qreal largeRatio;
if (m_id == QLatin1String(Constants::C_CURRENT_LINE)) {
- smallRatio = .15;
- largeRatio = .3;
+ smallRatio = .3;
+ largeRatio = .6;
} else {
smallRatio = .05;
largeRatio = .4;
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "context.h"
+#include "rule.h"
+#include "reuse.h"
+#include "dynamicrule.h"
+#include "highlightdefinition.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+Context::Context() : m_fallthrough(false), m_dynamic(false)
+{}
+
+Context::Context(const Context &context) :
+ m_id(context.m_id), m_name(context.m_name), m_lineBeginContext(context.m_lineBeginContext),
+ m_lineEndContext(context.m_lineEndContext), m_fallthroughContext(context.m_fallthroughContext),
+ m_itemData(context.m_itemData), m_fallthrough(context.m_fallthrough),
+ m_dynamic(context.m_dynamic), m_instructions(context.m_instructions),
+ m_definition(context.m_definition)
+{
+ // Rules need to be deeply copied because of dynamic contexts.
+ foreach (const QSharedPointer<Rule> &rule, context.m_rules)
+ m_rules.append(QSharedPointer<Rule>(rule->clone()));
+}
+
+const Context &Context::operator=(Context copy)
+{
+ swap(copy);
+ return *this;
+}
+
+Context::~Context()
+{}
+
+void Context::swap(Context &context)
+{
+ qSwap(m_id, context.m_id);
+ qSwap(m_name, context.m_name);
+ qSwap(m_lineBeginContext, context.m_lineBeginContext);
+ qSwap(m_lineEndContext, context.m_lineEndContext);
+ qSwap(m_fallthroughContext, context.m_fallthroughContext);
+ qSwap(m_itemData, context.m_itemData);
+ qSwap(m_fallthrough, context.m_fallthrough);
+ qSwap(m_dynamic, context.m_dynamic);
+ qSwap(m_rules, context.m_rules);
+ qSwap(m_instructions, context.m_instructions);
+ qSwap(m_definition, context.m_definition);
+}
+
+void Context::configureId(const int unique)
+{ m_id.append(QString::number(unique)); }
+
+const QString &Context::id() const
+{ return m_id; }
+
+void Context::setName(const QString &name)
+{
+ m_name = name;
+ m_id = name;
+}
+
+const QString &Context::name() const
+{ return m_name; }
+
+void Context::setLineBeginContext(const QString &context)
+{ m_lineBeginContext = context; }
+
+const QString &Context::lineBeginContext() const
+{ return m_lineBeginContext; }
+
+void Context::setLineEndContext(const QString &context)
+{ m_lineEndContext = context; }
+
+const QString &Context::lineEndContext() const
+{ return m_lineEndContext; }
+
+void Context::setFallthroughContext(const QString &context)
+{ m_fallthroughContext = context; }
+
+const QString &Context::fallthroughContext() const
+{ return m_fallthroughContext; }
+
+void Context::setItemData(const QString &itemData)
+{ m_itemData = itemData; }
+
+const QString &Context::itemData() const
+{ return m_itemData; }
+
+void Context::setFallthrough(const QString &fallthrough)
+{ m_fallthrough = toBool(fallthrough); }
+
+bool Context::isFallthrough() const
+{ return m_fallthrough; }
+
+void Context::setDynamic(const QString &dynamic)
+{ m_dynamic = toBool(dynamic); }
+
+bool Context::isDynamic() const
+{ return m_dynamic; }
+
+void Context::updateDynamicRules(const QStringList &captures) const
+{
+ TextEditor::Internal::updateDynamicRules(m_rules, captures);
+}
+
+void Context::addRule(const QSharedPointer<Rule> &rule)
+{ m_rules.append(rule); }
+
+void Context::addRule(const QSharedPointer<Rule> &rule, int index)
+{ m_rules.insert(index, rule); }
+
+const QList<QSharedPointer<Rule> > & Context::rules() const
+{ return m_rules; }
+
+void Context::addIncludeRulesInstruction(const IncludeRulesInstruction &instruction)
+{ m_instructions.append(instruction); }
+
+const QList<IncludeRulesInstruction> &Context::includeRulesInstructions() const
+{ return m_instructions; }
+
+void Context::clearIncludeRulesInstructions()
+{ m_instructions.clear(); }
+
+void Context::setDefinition(const QSharedPointer<HighlightDefinition> &definition)
+{ m_definition = definition; }
+
+const QSharedPointer<HighlightDefinition> &Context::definition() const
+{ return m_definition; }
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef CONTEXT_H
+#define CONTEXT_H
+
+#include "includerulesinstruction.h"
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QSharedPointer>
+
+namespace TextEditor {
+namespace Internal {
+
+class Rule;
+class HighlightDefinition;
+
+class Context
+{
+public:
+ Context();
+ Context(const Context &context);
+ const Context &operator=(Context copy);
+ ~Context();
+
+ void configureId(const int unique);
+ const QString &id() const;
+
+ void setName(const QString &name);
+ const QString &name() const;
+
+ void setLineBeginContext(const QString &context);
+ const QString &lineBeginContext() const;
+
+ void setLineEndContext(const QString &context);
+ const QString &lineEndContext() const;
+
+ void setFallthroughContext(const QString &context);
+ const QString &fallthroughContext() const;
+
+ void setItemData(const QString &itemData);
+ const QString &itemData() const;
+
+ void setFallthrough(const QString &fallthrough);
+ bool isFallthrough() const;
+
+ void setDynamic(const QString &dynamic);
+ bool isDynamic() const;
+ void updateDynamicRules(const QStringList &captures) const;
+
+ void addRule(const QSharedPointer<Rule> &rule);
+ void addRule(const QSharedPointer<Rule> &rule, int index);
+ const QList<QSharedPointer<Rule> > &rules() const;
+
+ void addIncludeRulesInstruction(const IncludeRulesInstruction &instruction);
+ const QList<IncludeRulesInstruction> &includeRulesInstructions() const;
+ void clearIncludeRulesInstructions();
+
+ void setDefinition(const QSharedPointer<HighlightDefinition> &definition);
+ const QSharedPointer<HighlightDefinition> &definition() const;
+
+ void swap(Context &context);
+
+private:
+ QString m_id;
+ QString m_name;
+ QString m_lineBeginContext;
+ QString m_lineEndContext;
+ QString m_fallthroughContext;
+ QString m_itemData;
+ bool m_fallthrough;
+ bool m_dynamic;
+
+ QList<QSharedPointer<Rule> > m_rules;
+ QList<IncludeRulesInstruction> m_instructions;
+
+ QSharedPointer<HighlightDefinition> m_definition;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // CONTEXT_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "definitiondownloader.h"
+
+#include <QtCore/QLatin1Char>
+#include <QtCore/QEventLoop>
+#include <QtCore/QFile>
+#include <QtNetwork/QNetworkAccessManager>
+#include <QtNetwork/QNetworkRequest>
+#include <QtNetwork/QNetworkReply>
+
+using namespace TextEditor;
+using namespace Internal;
+
+DefinitionDownloader::DefinitionDownloader(const QUrl &url, const QString &localPath) :
+ m_url(url), m_localPath(localPath)
+{}
+
+void DefinitionDownloader::start()
+{
+ QNetworkReply *reply;
+ QNetworkAccessManager manager;
+
+ int currentAttempt = 0;
+ const int maxAttempts = 5;
+ while (currentAttempt < maxAttempts) {
+ reply = getData(&manager);
+ if (reply->error() != QNetworkReply::NoError)
+ break;
+
+ ++currentAttempt;
+ QVariant variant = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (variant.isValid() && currentAttempt < maxAttempts) {
+ m_url = variant.toUrl();
+ delete reply;
+ } else if (!variant.isValid()) {
+ saveData(reply);
+ break;
+ }
+ }
+
+ delete reply;
+}
+
+QNetworkReply *DefinitionDownloader::getData(QNetworkAccessManager *manager) const
+{
+ QNetworkRequest request(m_url);
+ QNetworkReply *reply = manager->get(request);
+
+ QEventLoop eventLoop;
+ connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
+ eventLoop.exec();
+
+ return reply;
+}
+
+void DefinitionDownloader::saveData(QNetworkReply *reply) const
+{
+ const QString &urlPath = m_url.path();
+ const QString &fileName =
+ urlPath.right(urlPath.length() - urlPath.lastIndexOf(QLatin1Char('/')) - 1);
+ QFile file(m_localPath + fileName);
+ if (!file.open(QIODevice::Text | QIODevice::WriteOnly))
+ return;
+ file.write(reply->readAll());
+ file.close();
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DEFINITIONDOWNLOADER_H
+#define DEFINITIONDOWNLOADER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QUrl>
+
+QT_BEGIN_NAMESPACE
+class QNetworkReply;
+class QNetworkAccessManager;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+namespace Internal {
+
+class DefinitionDownloader : public QObject
+{
+ Q_OBJECT
+public:
+ DefinitionDownloader(const QUrl &url, const QString &localPath);
+
+ void start();
+
+private:
+ QNetworkReply *getData(QNetworkAccessManager *manager) const;
+ void saveData(QNetworkReply *reply) const;
+
+ QUrl m_url;
+ QString m_localPath;
+};
+
+// Currently QtConcurrent::map does not support passing member functions for sequence of pointers
+// (only works for operator.*) which is the case for the downloaders held by the manager. Then the
+// reason for the following functor. If something is implemented (for example a type traits) to
+// handle operator->* in QtConcurrent::map this functor will not be necessary since it would be
+// possible to directly pass DefinitionDownloader::start.
+struct DownloaderStarter
+{
+ void operator()(DefinitionDownloader *downloader)
+ { downloader->start(); }
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // DEFINITIONDOWNLOADER_H
**
**************************************************************************/
-#include "TokenUnderCursor.h"
-#include "BackwardsScanner.h"
-#include <Token.h>
+#include "dynamicrule.h"
+#include "reuse.h"
-#include <QTextCursor>
-#include <QTextBlock>
-#include <climits>
+using namespace TextEditor;
+using namespace Internal;
-using namespace CPlusPlus;
+DynamicRule::DynamicRule() : m_active(false)
+{}
-TokenUnderCursor::TokenUnderCursor()
-{ }
+DynamicRule::~DynamicRule()
+{}
-TokenUnderCursor::~TokenUnderCursor()
-{ }
+void DynamicRule::setActive(const QString &active)
+{ m_active = toBool(active); }
-SimpleToken TokenUnderCursor::operator()(const QTextCursor &cursor, QTextBlock *b)
+bool DynamicRule::isActive() const
+{ return m_active; }
+
+void DynamicRule::replaceExpressions(const QStringList &captures)
{
- SimpleLexer tokenize;
- tokenize.setObjCEnabled(true);
- tokenize.setSkipComments(false);
+ doReplaceExpressions(captures);
+ updateDynamicRules(childs(), captures);
+}
- QTextBlock block = cursor.block();
- int column = cursor.position() - cursor.block().position();
+namespace TextEditor {
+namespace Internal {
- _text = block.text();
- _tokens = tokenize(_text, BackwardsScanner::previousBlockState(block));
- for (int index = _tokens.size() - 1; index != -1; --index) {
- const SimpleToken &tk = _tokens.at(index);
- if (tk.position() < column) {
- if (b)
- *b = block;
- return tk;
- }
+void updateDynamicRules(const QList<QSharedPointer<Rule> > &rules, const QStringList &captures)
+{
+ foreach (QSharedPointer<Rule> rule, rules) {
+ DynamicRule *dynamicRule = dynamic_cast<DynamicRule *>(rule.data());
+ if (dynamicRule && dynamicRule->isActive())
+ dynamicRule->replaceExpressions(captures);
}
-
- return SimpleToken();
}
+
+} // namespace Internal
+} // namespace TextEditor
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DYNAMICRULE_H
+#define DYNAMICRULE_H
+
+#include "rule.h"
+
+QT_BEGIN_NAMESPACE
+class QStringList;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+namespace Internal {
+
+class DynamicRule : public Rule
+{
+public:
+ DynamicRule();
+ virtual ~DynamicRule();
+
+ void setActive(const QString &active);
+ bool isActive() const;
+
+ virtual void replaceExpressions(const QStringList &captures);
+
+private:
+ virtual void doReplaceExpressions(const QStringList &captures) = 0;
+
+ bool m_active;
+};
+
+void updateDynamicRules(const QList<QSharedPointer<Rule> > &rules, const QStringList &captures);
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // DYNAMICRULE_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlightdefinition.h"
+#include "highlighterexception.h"
+#include "context.h"
+#include "keywordlist.h"
+#include "itemdata.h"
+#include "reuse.h"
+
+#include <QLatin1String>
+
+using namespace TextEditor;
+using namespace Internal;
+
+HighlightDefinition::HighlightDefinition() :
+ m_delimiters(QLatin1String(".():!+,-<=>%&/;?[]^{|}~\\*, \t")),
+ m_singleLineCommentAfterWhiteSpaces(false),
+ m_keywordCaseSensitivity(Qt::CaseSensitive)
+{}
+
+HighlightDefinition::~HighlightDefinition()
+{}
+
+template <class Element, class Container>
+QSharedPointer<Element> HighlightDefinition::
+GenericHelper::create(const QString &name, Container &container)
+{
+ if (name.isEmpty())
+ throw HighlighterException();
+
+ if (container.contains(name))
+ throw HighlighterException();
+
+ return container.insert(name, QSharedPointer<Element>(new Element)).value();
+}
+
+template <class Element, class Container>
+QSharedPointer<Element> HighlightDefinition::
+GenericHelper::find(const QString &name, const Container &container) const
+{
+ typename Container::const_iterator it = container.find(name);
+ if (it == container.end())
+ throw HighlighterException();
+
+ return it.value();
+}
+
+QSharedPointer<KeywordList> HighlightDefinition::createKeywordList(const QString &list)
+{ return m_helper.create<KeywordList>(list, m_lists); }
+
+QSharedPointer<KeywordList> HighlightDefinition::keywordList(const QString &list)
+{ return m_helper.find<KeywordList>(list, m_lists); }
+
+QSharedPointer<Context> HighlightDefinition::createContext(const QString &context, bool initial)
+{
+ if (initial)
+ m_initialContext = context;
+
+ QSharedPointer<Context> newContext = m_helper.create<Context>(context, m_contexts);
+ newContext->setName(context);
+ return newContext;
+}
+
+QSharedPointer<Context> HighlightDefinition::initialContext() const
+{ return m_helper.find<Context>(m_initialContext, m_contexts); }
+
+QSharedPointer<Context> HighlightDefinition::context(const QString &context) const
+{ return m_helper.find<Context>(context, m_contexts); }
+
+const QHash<QString, QSharedPointer<Context> > &HighlightDefinition::contexts() const
+{ return m_contexts; }
+
+QSharedPointer<ItemData> HighlightDefinition::createItemData(const QString &itemData)
+{ return m_helper.create<ItemData>(itemData, m_itemsData); }
+
+QSharedPointer<ItemData> HighlightDefinition::itemData(const QString &itemData) const
+{ return m_helper.find<ItemData>(itemData, m_itemsData); }
+
+void HighlightDefinition::setSingleLineComment(const QString &start)
+{ m_singleLineComment = start; }
+
+const QString &HighlightDefinition::singleLineComment() const
+{ return m_singleLineComment; }
+
+void HighlightDefinition::setCommentAfterWhitespaces(const QString &after)
+{
+ if (after == QLatin1String("afterwhitespace"))
+ m_singleLineCommentAfterWhiteSpaces = true;
+}
+
+bool HighlightDefinition::isCommentAfterWhiteSpaces() const
+{ return m_singleLineCommentAfterWhiteSpaces; }
+
+void HighlightDefinition::setMultiLineCommentStart(const QString &start)
+{ m_multiLineCommentStart = start; }
+
+const QString &HighlightDefinition::multiLineCommentStart() const
+{ return m_multiLineCommentStart; }
+
+void HighlightDefinition::setMultiLineCommentEnd(const QString &end)
+{ m_multiLineCommentEnd = end; }
+
+const QString &HighlightDefinition::multiLineCommentEnd() const
+{ return m_multiLineCommentEnd; }
+
+void HighlightDefinition::setMultiLineCommentRegion(const QString ®ion)
+{ m_multiLineCommentRegion = region; }
+
+const QString &HighlightDefinition::multiLineCommentRegion() const
+{ return m_multiLineCommentRegion; }
+
+void HighlightDefinition::removeDelimiters(const QString &characters)
+{
+ for (int i = 0; i < characters.length(); ++i)
+ m_delimiters.remove(characters.at(i));
+}
+
+void HighlightDefinition::addDelimiters(const QString &characters)
+{
+ for (int i = 0; i < characters.length(); ++i) {
+ if (!m_delimiters.contains(characters.at(i)))
+ m_delimiters.append(characters.at(i));
+ }
+}
+
+bool HighlightDefinition::isDelimiter(const QChar &character) const
+{
+ if (m_delimiters.contains(character))
+ return true;
+ return false;
+}
+
+void HighlightDefinition::setKeywordsSensitive(const QString &sensitivity)
+{
+ if (!sensitivity.isEmpty())
+ m_keywordCaseSensitivity = toCaseSensitivity(toBool(sensitivity));
+}
+
+Qt::CaseSensitivity HighlightDefinition::keywordsSensitive() const
+{ return m_keywordCaseSensitivity; }
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTDEFINITION_H
+#define HIGHLIGHTDEFINITION_H
+
+#include <QtCore/QString>
+#include <QtCore/QHash>
+#include <QtCore/QSharedPointer>
+
+namespace TextEditor {
+namespace Internal {
+
+class KeywordList;
+class Context;
+class ItemData;
+
+class HighlightDefinition
+{
+public:
+ HighlightDefinition();
+ ~HighlightDefinition();
+
+ QSharedPointer<KeywordList> createKeywordList(const QString &list);
+ QSharedPointer<KeywordList> keywordList(const QString &list);
+
+ QSharedPointer<Context> createContext(const QString &context, bool initial);
+ QSharedPointer<Context> initialContext() const;
+ QSharedPointer<Context> context(const QString &context) const;
+ const QHash<QString, QSharedPointer<Context> > &contexts() const;
+
+ QSharedPointer<ItemData> createItemData(const QString &itemData);
+ QSharedPointer<ItemData> itemData(const QString &itemData) const;
+
+ void setKeywordsSensitive(const QString &sensitivity);
+ Qt::CaseSensitivity keywordsSensitive() const;
+
+ void addDelimiters(const QString &characters);
+ void removeDelimiters(const QString &characters);
+ bool isDelimiter(const QChar &character) const;
+
+ void setSingleLineComment(const QString &start);
+ const QString &singleLineComment() const;
+
+ void setCommentAfterWhitespaces(const QString &after);
+ bool isCommentAfterWhiteSpaces() const;
+
+ void setMultiLineCommentStart(const QString &start);
+ const QString &multiLineCommentStart() const;
+
+ void setMultiLineCommentEnd(const QString &end);
+ const QString &multiLineCommentEnd() const;
+
+ void setMultiLineCommentRegion(const QString ®ion);
+ const QString &multiLineCommentRegion() const;
+
+private:
+ Q_DISABLE_COPY(HighlightDefinition)
+
+ struct GenericHelper
+ {
+ template <class Element, class Container>
+ QSharedPointer<Element> create(const QString &name, Container &container);
+
+ template <class Element, class Container>
+ QSharedPointer<Element> find(const QString &name, const Container &container) const;
+ };
+ GenericHelper m_helper;
+
+ QHash<QString, QSharedPointer<KeywordList> > m_lists;
+ QHash<QString, QSharedPointer<Context> > m_contexts;
+ QHash<QString, QSharedPointer<ItemData> > m_itemsData;
+
+ QString m_initialContext;
+
+ QString m_delimiters;
+
+ QString m_singleLineComment;
+ bool m_singleLineCommentAfterWhiteSpaces;
+
+ QString m_multiLineCommentStart;
+ QString m_multiLineCommentEnd;
+ QString m_multiLineCommentRegion;
+
+ Qt::CaseSensitivity m_keywordCaseSensitivity;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // HIGHLIGHTDEFINITION_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlightdefinitionhandler.h"
+#include "highlightdefinition.h"
+#include "specificrules.h"
+#include "itemdata.h"
+#include "keywordlist.h"
+#include "context.h"
+#include "reuse.h"
+#include "manager.h"
+#include "highlighterexception.h"
+
+#include <QLatin1String>
+
+using namespace TextEditor;
+using namespace Internal;
+
+namespace {
+ static const QLatin1String kName("name");
+ static const QLatin1String kList("list");
+ static const QLatin1String kItem("item");
+ static const QLatin1String kContext("context");
+ static const QLatin1String kAttribute("attribute");
+ static const QLatin1String kDynamic("dynamic");
+ static const QLatin1String kFallthrough("fallthrough");
+ static const QLatin1String kLineEndContext("lineEndContext");
+ static const QLatin1String kLineBeginContext("lineBeginContext");
+ static const QLatin1String kFallthroughContext("fallthroughContext");
+ static const QLatin1String kBeginRegion("beginRegion");
+ static const QLatin1String kEndRegion("endRegion");
+ static const QLatin1String kLookAhead("lookAhead");
+ static const QLatin1String kFirstNonSpace("firstNonSpace");
+ static const QLatin1String kColumn("column");
+ static const QLatin1String kItemData("itemData");
+ static const QLatin1String kDefStyleNum("defStyleNum");
+ static const QLatin1String kColor("color");
+ static const QLatin1String kSelColor("selColor");
+ static const QLatin1String kItalic("italic");
+ static const QLatin1String kBold("bold");
+ static const QLatin1String kUnderline("underline");
+ static const QLatin1String kStrikeout("strikeout");
+ static const QLatin1String kChar("char");
+ static const QLatin1String kChar1("char1");
+ static const QLatin1String kString("String");
+ static const QLatin1String kInsensitive("insensitive");
+ static const QLatin1String kMinimal("minimal");
+ static const QLatin1String kKeywords("keywords");
+ static const QLatin1String kCaseSensitive("casesensitive");
+ static const QLatin1String kWeakDeliminator("weakDeliminator");
+ static const QLatin1String kAdditionalDeliminator("additionalDeliminator");
+ static const QLatin1String kWordWrapDeliminator("wordWrapDeliminator");
+ static const QLatin1String kComment("comment");
+ static const QLatin1String kPosition("position");
+ static const QLatin1String kSingleLine("singleline");
+ static const QLatin1String kMultiLine("multiline");
+ static const QLatin1String kStart("start");
+ static const QLatin1String kEnd("end");
+ static const QLatin1String kRegion("region");
+ static const QLatin1String kDetectChar("DetectChar");
+ static const QLatin1String kDetect2Chars("Detect2Chars");
+ static const QLatin1String kAnyChar("AnyChar");
+ static const QLatin1String kStringDetect("StringDetect");
+ static const QLatin1String kRegExpr("RegExpr");
+ static const QLatin1String kKeyword("keyword");
+ static const QLatin1String kInt("Int");
+ static const QLatin1String kFloat("Float");
+ static const QLatin1String kHlCOct("HlCOct");
+ static const QLatin1String kHlCHex("HlCHex");
+ static const QLatin1String kHlCStringChar("HlCStringChar");
+ static const QLatin1String kHlCChar("HlCChar");
+ static const QLatin1String kRangeDetect("RangeDetect");
+ static const QLatin1String kLineContinue("LineContinue");
+ static const QLatin1String kIncludeRules("IncludeRules");
+ static const QLatin1String kDetectSpaces("DetectSpaces");
+ static const QLatin1String kDetectIdentifier("DetectIdentifier");
+ static const QLatin1String kLanguage("language");
+ static const QLatin1String kExtensions("extensions");
+ static const QLatin1String kIncludeAttrib("includeAttrib");
+ static const QLatin1String kHash("#");
+ static const QLatin1String kDoubleHash("##");
+}
+
+HighlightDefinitionHandler::
+HighlightDefinitionHandler(const QSharedPointer<HighlightDefinition> &definition) :
+ m_definition(definition),
+ m_processingKeyword(false),
+ m_initialContext(true)
+{}
+
+HighlightDefinitionHandler::~HighlightDefinitionHandler()
+{}
+
+bool HighlightDefinitionHandler::startDocument()
+{
+ return true;
+}
+
+bool HighlightDefinitionHandler::endDocument()
+{
+ processIncludeRules();
+ return true;
+}
+
+bool HighlightDefinitionHandler::startElement(const QString &,
+ const QString &,
+ const QString &qName,
+ const QXmlAttributes &atts)
+{
+ if (qName == kList) {
+ listElementStarted(atts);
+ } else if (qName == kItem) {
+ itemElementStarted();
+ } else if (qName == kContext) {
+ contextElementStarted(atts);
+ } else if (qName == kItemData) {
+ itemDataElementStarted(atts);
+ } else if (qName == kComment) {
+ commentElementStarted(atts);
+ } else if (qName == kKeywords) {
+ keywordsElementStarted(atts);
+ } else if (qName == kDetectChar) {
+ detectCharStarted(atts);
+ } else if (qName == kDetect2Chars) {
+ detect2CharsStarted(atts);
+ } else if (qName == kAnyChar) {
+ anyCharStarted(atts);
+ } else if (qName == kStringDetect) {
+ stringDetectedStarted(atts);
+ } else if (qName == kRegExpr) {
+ regExprStarted(atts);
+ } else if (qName == kKeyword) {
+ keywordStarted(atts);
+ } else if (qName == kInt) {
+ intStarted(atts);
+ } else if (qName == kFloat) {
+ floatStarted(atts);
+ } else if (qName == kHlCOct) {
+ hlCOctStarted(atts);
+ } else if (qName == kHlCHex) {
+ hlCHexStarted(atts);
+ } else if (qName == kHlCStringChar) {
+ hlCStringCharStarted(atts);
+ } else if (qName == kHlCChar) {
+ hlCCharStarted(atts);
+ } else if (qName == kRangeDetect) {
+ rangeDetectStarted(atts);
+ } else if (qName == kLineContinue) {
+ lineContinue(atts);
+ } else if (qName == kIncludeRules) {
+ includeRulesStarted(atts);
+ } else if (qName == kDetectSpaces) {
+ detectSpacesStarted(atts);
+ } else if (qName == kDetectIdentifier) {
+ detectIdentifier(atts);
+ }
+
+ return true;
+}
+
+bool HighlightDefinitionHandler::endElement(const QString &, const QString &, const QString &qName)
+{
+ if (qName == kItem) {
+ m_currentList->addKeyword(m_currentKeyword.trimmed());
+ m_processingKeyword = false;
+ } else if (qName == kDetectChar || qName == kDetect2Chars || qName == kAnyChar ||
+ qName == kStringDetect || qName == kRegExpr || qName == kKeyword || qName == kInt ||
+ qName == kFloat || qName == kHlCOct || qName == kHlCHex || qName == kHlCStringChar ||
+ qName == kHlCChar || qName == kRangeDetect || qName == kLineContinue ||
+ qName == kDetectSpaces || qName == kDetectIdentifier) {
+ m_currentRule.pop();
+ }
+
+ return true;
+}
+
+bool HighlightDefinitionHandler::characters(const QString& ch)
+{
+ // Character data of an element may be reported in more than one chunk.
+ if (m_processingKeyword)
+ m_currentKeyword.append(ch);
+
+ return true;
+}
+
+void HighlightDefinitionHandler::listElementStarted(const QXmlAttributes &atts)
+{
+ m_currentList = m_definition->createKeywordList(atts.value(kName));
+}
+
+void HighlightDefinitionHandler::itemElementStarted()
+{
+ m_currentKeyword.clear();
+ m_processingKeyword = true;
+}
+
+void HighlightDefinitionHandler::contextElementStarted(const QXmlAttributes &atts)
+{
+ m_currentContext = m_definition->createContext(atts.value(kName), m_initialContext);
+ m_currentContext->setDefinition(m_definition);
+ m_currentContext->setItemData(atts.value(kAttribute));
+ m_currentContext->setDynamic(atts.value(kDynamic));
+ m_currentContext->setFallthrough(atts.value(kFallthrough));
+ m_currentContext->setFallthroughContext(atts.value(kFallthroughContext));
+ m_currentContext->setLineBeginContext(atts.value(kLineBeginContext));
+ m_currentContext->setLineEndContext(atts.value(kLineEndContext));
+
+ m_initialContext = false;
+}
+
+void HighlightDefinitionHandler::ruleElementStarted(const QXmlAttributes &atts,
+ const QSharedPointer<Rule> &rule)
+{
+ // The definition of a rule is not necessarily the same of its enclosing context because of
+ // externally included rules.
+ rule->setDefinition(m_definition);
+ rule->setItemData(atts.value(kAttribute));
+ rule->setContext(atts.value(kContext));
+ rule->setBeginRegion(atts.value(kBeginRegion));
+ rule->setEndRegion(atts.value(kEndRegion));
+ rule->setLookAhead(atts.value(kLookAhead));
+ rule->setFirstNonSpace(atts.value(kFirstNonSpace));
+ rule->setColumn(atts.value(kColumn));
+
+ if (m_currentRule.isEmpty())
+ m_currentContext->addRule(rule);
+ else
+ m_currentRule.top()->addChild(rule);
+
+ m_currentRule.push(rule);
+}
+
+void HighlightDefinitionHandler::itemDataElementStarted(const QXmlAttributes &atts) const
+{
+ QSharedPointer<ItemData> itemData = m_definition->createItemData(atts.value(kName));
+ itemData->setStyle(atts.value(kDefStyleNum));
+ itemData->setColor(atts.value(kColor));
+ itemData->setSelectionColor(atts.value(kSelColor));
+ itemData->setItalic(atts.value(kItalic));
+ itemData->setBold(atts.value(kBold));
+ itemData->setUnderlined(atts.value(kUnderline));
+ itemData->setStrikedOut(atts.value(kStrikeout));
+}
+
+void HighlightDefinitionHandler::commentElementStarted(const QXmlAttributes &atts) const
+{
+ const QString &commentType = atts.value(kName);
+ if (commentType.compare(kSingleLine, Qt::CaseInsensitive) == 0) {
+ m_definition->setSingleLineComment(atts.value(kStart));
+ m_definition->setCommentAfterWhitespaces(atts.value(kPosition));
+ } else if (commentType.compare(kMultiLine, Qt::CaseInsensitive) == 0) {
+ m_definition->setMultiLineCommentStart(atts.value(kStart));
+ m_definition->setMultiLineCommentEnd(atts.value(kEnd));
+ m_definition->setMultiLineCommentRegion(atts.value(kRegion));
+ }
+}
+
+void HighlightDefinitionHandler::keywordsElementStarted(const QXmlAttributes &atts) const
+{
+ // Global case sensitivity appears last in the document (required by dtd) and is set here.
+ m_definition->setKeywordsSensitive(atts.value(kCaseSensitive));
+ m_definition->removeDelimiters(atts.value(kWeakDeliminator));
+ m_definition->addDelimiters(atts.value(kAdditionalDeliminator));
+ //@todo: wordWrapDelimiters?
+}
+
+void HighlightDefinitionHandler::detectCharStarted(const QXmlAttributes &atts)
+{
+ DetectCharRule *rule = new DetectCharRule;
+ rule->setChar(atts.value(kChar));
+ rule->setActive(atts.value(kDynamic));
+ ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::detect2CharsStarted(const QXmlAttributes &atts)
+{
+ Detect2CharsRule *rule = new Detect2CharsRule;
+ rule->setChar(atts.value(kChar));
+ rule->setChar1(atts.value(kChar1));
+ rule->setActive(atts.value(kDynamic));
+ ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::anyCharStarted(const QXmlAttributes &atts)
+{
+ AnyCharRule *rule = new AnyCharRule;
+ rule->setCharacterSet(atts.value(kString));
+ ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::stringDetectedStarted(const QXmlAttributes &atts)
+{
+ StringDetectRule *rule = new StringDetectRule;
+ rule->setString(atts.value(kString));
+ rule->setInsensitive(atts.value(kInsensitive));
+ rule->setActive(atts.value(kDynamic));
+ ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::regExprStarted(const QXmlAttributes &atts)
+{
+ RegExprRule *rule = new RegExprRule;
+ rule->setPattern(atts.value(kString));
+ rule->setMinimal(atts.value(kMinimal));
+ rule->setInsensitive(atts.value(kInsensitive));
+ rule->setActive(atts.value(kDynamic));
+ ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::keywordStarted(const QXmlAttributes &atts)
+{
+ KeywordRule *rule = new KeywordRule(m_definition);
+ rule->setList(atts.value(kString));
+ rule->setInsensitive(atts.value(kInsensitive));
+ ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::intStarted(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new IntRule));
+}
+
+void HighlightDefinitionHandler::floatStarted(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new FloatRule));
+}
+
+void HighlightDefinitionHandler::hlCOctStarted(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new HlCOctRule));
+}
+
+void HighlightDefinitionHandler::hlCHexStarted(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new HlCHexRule));
+}
+
+void HighlightDefinitionHandler::hlCStringCharStarted(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new HlCStringCharRule));
+}
+
+void HighlightDefinitionHandler::hlCCharStarted(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new HlCCharRule));
+}
+
+void HighlightDefinitionHandler::rangeDetectStarted(const QXmlAttributes &atts)
+{
+ RangeDetectRule *rule = new RangeDetectRule;
+ rule->setChar(atts.value(kChar));
+ rule->setChar1(atts.value(kChar1));
+ ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::lineContinue(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new LineContinueRule));
+}
+
+void HighlightDefinitionHandler::includeRulesStarted(const QXmlAttributes &atts)
+{
+ // Include rules are treated as instructions for latter processing.
+ IncludeRulesInstruction instruction(atts.value(kContext), m_currentContext->rules().size(),
+ atts.value(kIncludeAttrib));
+
+ // Include rules (as many others) are not allowed as a child.
+ m_currentContext->addIncludeRulesInstruction(instruction);
+}
+
+void HighlightDefinitionHandler::detectSpacesStarted(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new DetectSpacesRule));
+}
+
+void HighlightDefinitionHandler::detectIdentifier(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new DetectIdentifierRule));
+}
+
+void HighlightDefinitionHandler::processIncludeRules() const
+{
+ const QHash<QString, QSharedPointer<Context> > &allContexts = m_definition->contexts();
+ foreach (const QSharedPointer<Context> &context, allContexts)
+ processIncludeRules(context);
+}
+
+void HighlightDefinitionHandler::processIncludeRules(const QSharedPointer<Context> &context) const
+{
+ if (context->includeRulesInstructions().isEmpty())
+ return;
+
+ int rulesIncluded = 0;
+ const QList<IncludeRulesInstruction> &instructions = context->includeRulesInstructions();
+ foreach (const IncludeRulesInstruction &instruction, instructions) {
+
+ QSharedPointer<Context> sourceContext;
+ const QString &sourceName = instruction.sourceContext();
+ if (sourceName.startsWith(kDoubleHash)) {
+ // This refers to an external definition. The rules included are the ones from its
+ // initial context. Others contexts and rules from the external definition will work
+ // transparently to the highlighter. This is because contexts and rules know the
+ // definition they are from.
+ QString externalName = QString::fromRawData(sourceName.unicode() + 2,
+ sourceName.length() - 2);
+ const QString &id = Manager::instance()->definitionIdByName(externalName);
+
+ // If there is an incorrect circular dependency among definitions this is skipped.
+ if (Manager::instance()->isBuildingDefinition(id))
+ continue;
+
+ const QSharedPointer<HighlightDefinition> &externalDefinition =
+ Manager::instance()->definition(id);
+ if (externalDefinition.isNull())
+ continue;
+
+ sourceContext = externalDefinition->initialContext();
+ } else if (!sourceName.startsWith(kHash)) {
+ sourceContext = m_definition->context(sourceName);
+
+ // Recursion is done only for context direct rules. Child rules are not processed
+ // because they cannot be include rules.
+ processIncludeRules(sourceContext);
+ } else {
+ continue;
+ }
+
+ if (instruction.replaceItemData()) {
+ context->setItemData(sourceContext->itemData());
+ context->setDefinition(sourceContext->definition());
+ }
+
+ foreach (QSharedPointer<Rule> rule, sourceContext->rules()) {
+ context->addRule(rule, instruction.indexHint() + rulesIncluded);
+ ++rulesIncluded;
+ }
+ }
+ context->clearIncludeRulesInstructions();
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTDEFINITIONHANDLER_H
+#define HIGHLIGHTDEFINITIONHANDLER_H
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QStack>
+
+#include <QtXml/QXmlDefaultHandler>
+
+namespace TextEditor {
+namespace Internal {
+
+class KeywordList;
+class Context;
+class Rule;
+class HighlightDefinition;
+
+class HighlightDefinitionHandler : public QXmlDefaultHandler
+{
+public:
+ HighlightDefinitionHandler(const QSharedPointer<HighlightDefinition> &definition);
+ ~HighlightDefinitionHandler();
+
+ bool startDocument();
+ bool endDocument();
+ bool startElement(const QString &namespaceURI, const QString &localName,
+ const QString &qName, const QXmlAttributes &atts);
+ bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName);
+ bool characters(const QString &ch);
+
+private:
+ void listElementStarted(const QXmlAttributes &atts);
+ void itemElementStarted();
+ void contextElementStarted(const QXmlAttributes &atts);
+ void itemDataElementStarted(const QXmlAttributes &atts) const;
+ void commentElementStarted(const QXmlAttributes &atts) const;
+ void keywordsElementStarted(const QXmlAttributes &atts) const;
+ void ruleElementStarted(const QXmlAttributes &atts, const QSharedPointer<Rule> &rule);
+
+ // Specific rules.
+ void detectCharStarted(const QXmlAttributes &atts);
+ void detect2CharsStarted(const QXmlAttributes &atts);
+ void anyCharStarted(const QXmlAttributes &atts);
+ void stringDetectedStarted(const QXmlAttributes &atts);
+ void regExprStarted(const QXmlAttributes &atts);
+ void keywordStarted(const QXmlAttributes &atts);
+ void intStarted(const QXmlAttributes &atts);
+ void floatStarted(const QXmlAttributes &atts);
+ void hlCOctStarted(const QXmlAttributes &atts);
+ void hlCHexStarted(const QXmlAttributes &atts);
+ void hlCStringCharStarted(const QXmlAttributes &atts);
+ void hlCCharStarted(const QXmlAttributes &atts);
+ void rangeDetectStarted(const QXmlAttributes &atts);
+ void lineContinue(const QXmlAttributes &atts);
+ void includeRulesStarted(const QXmlAttributes &atts);
+ void detectSpacesStarted(const QXmlAttributes &atts);
+ void detectIdentifier(const QXmlAttributes &atts);
+
+ void processIncludeRules() const;
+ void processIncludeRules(const QSharedPointer<Context> &context) const;
+
+ QSharedPointer<HighlightDefinition> m_definition;
+
+ bool m_processingKeyword;
+ QString m_currentKeyword;
+ QSharedPointer<KeywordList> m_currentList;
+ QSharedPointer<Context> m_currentContext;
+ QStack<QSharedPointer<Rule> > m_currentRule;
+
+ bool m_initialContext;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // HIGHLIGHTDEFINITIONHANDLER_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlightdefinitionmetadata.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+const QLatin1String HighlightDefinitionMetaData::kName("name");
+const QLatin1String HighlightDefinitionMetaData::kExtensions("extensions");
+const QLatin1String HighlightDefinitionMetaData::kMimeType("mimetype");
+const QLatin1String HighlightDefinitionMetaData::kVersion("version");
+const QLatin1String HighlightDefinitionMetaData::kUrl("url");
+
+HighlightDefinitionMetaData::HighlightDefinitionMetaData()
+{}
+
+void HighlightDefinitionMetaData::setName(const QString &name)
+{ m_name = name; }
+
+const QString &HighlightDefinitionMetaData::name() const
+{ return m_name; }
+
+void HighlightDefinitionMetaData::setVersion(const QString &version)
+{ m_version = version; }
+
+const QString &HighlightDefinitionMetaData::version() const
+{ return m_version; }
+
+void HighlightDefinitionMetaData::setPatterns(const QStringList &patterns)
+{ m_patterns = patterns; }
+
+const QStringList &HighlightDefinitionMetaData::patterns() const
+{ return m_patterns; }
+
+void HighlightDefinitionMetaData::setMimeTypes(const QStringList &mimeTypes)
+{ m_mimeTypes = mimeTypes; }
+
+const QStringList &HighlightDefinitionMetaData::mimeTypes() const
+{ return m_mimeTypes; }
+
+void HighlightDefinitionMetaData::setUrl(const QUrl &url)
+{ m_url = url; }
+
+const QUrl &HighlightDefinitionMetaData::url() const
+{ return m_url; }
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTDEFINITIONMETADATA_H
+#define HIGHLIGHTDEFINITIONMETADATA_H
+
+#include <QtCore/QString>
+#include <QtCore/QLatin1String>
+#include <QtCore/QStringList>
+#include <QtCore/QUrl>
+
+namespace TextEditor {
+namespace Internal {
+
+class HighlightDefinitionMetaData
+{
+public:
+ HighlightDefinitionMetaData();
+
+ void setName(const QString &name);
+ const QString &name() const;
+
+ void setVersion(const QString &version);
+ const QString &version() const;
+
+ void setPatterns(const QStringList &patterns);
+ const QStringList &patterns() const;
+
+ void setMimeTypes(const QStringList &mimeTypes);
+ const QStringList &mimeTypes() const;
+
+ void setUrl(const QUrl &url);
+ const QUrl &url() const;
+
+ static const QLatin1String kName;
+ static const QLatin1String kExtensions;
+ static const QLatin1String kMimeType;
+ static const QLatin1String kVersion;
+ static const QLatin1String kUrl;
+
+private:
+ QString m_name;
+ QString m_version;
+ QStringList m_patterns;
+ QStringList m_mimeTypes;
+ QUrl m_url;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // HIGHLIGHTDEFINITIONMETADATA_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlighter.h"
+#include "highlightdefinition.h"
+#include "context.h"
+#include "rule.h"
+#include "itemdata.h"
+#include "highlighterexception.h"
+#include "progressdata.h"
+#include "reuse.h"
+
+#include <QtCore/QLatin1String>
+#include <QtCore/QLatin1Char>
+
+using namespace TextEditor;
+using namespace Internal;
+
+namespace {
+ static const QLatin1String kStay("#stay");
+ static const QLatin1String kPop("#pop");
+ static const QLatin1Char kBackSlash('\\');
+ static const QLatin1Char kHash('#');
+}
+
+const Highlighter::KateFormatMap Highlighter::m_kateFormats;
+
+Highlighter::Highlighter(QTextDocument *parent) :
+ QSyntaxHighlighter(parent),
+ m_persistentStatesCounter(PersistentsStart),
+ m_dynamicContextsCounter(0),
+ m_isBroken(false)
+{}
+
+Highlighter::~Highlighter()
+{}
+
+Highlighter::BlockData::BlockData()
+{}
+
+Highlighter::BlockData::~BlockData()
+{}
+
+Highlighter::KateFormatMap::KateFormatMap()
+{
+ m_ids.insert(QLatin1String("dsNormal"), Highlighter::Normal);
+ m_ids.insert(QLatin1String("dsKeyword"), Highlighter::Keyword);
+ m_ids.insert(QLatin1String("dsDataType"), Highlighter::DataType);
+ m_ids.insert(QLatin1String("dsDecVal"), Highlighter::Decimal);
+ m_ids.insert(QLatin1String("dsBaseN"), Highlighter::BaseN);
+ m_ids.insert(QLatin1String("dsFloat"), Highlighter::Float);
+ m_ids.insert(QLatin1String("dsChar"), Highlighter::Char);
+ m_ids.insert(QLatin1String("dsString"), Highlighter::String);
+ m_ids.insert(QLatin1String("dsComment"), Highlighter::Comment);
+ m_ids.insert(QLatin1String("dsOthers"), Highlighter::Others);
+ m_ids.insert(QLatin1String("dsAlert"), Highlighter::Alert);
+ m_ids.insert(QLatin1String("dsFunction"), Highlighter::Function);
+ m_ids.insert(QLatin1String("dsRegionMarker"), Highlighter::RegionMarker);
+ m_ids.insert(QLatin1String("dsError"), Highlighter::Error);
+}
+
+void Highlighter::configureFormat(TextFormatId id, const QTextCharFormat &format)
+{
+ m_creatorFormats[id] = format;
+}
+
+void Highlighter::setDefaultContext(const QSharedPointer<Context> &defaultContext)
+{
+ m_defaultContext = defaultContext;
+ m_persistentStates.insert(m_defaultContext->name(), Default);
+}
+
+void Highlighter::highlightBlock(const QString &text)
+{
+ if (!m_defaultContext.isNull() && !m_isBroken) {
+ try {
+ setupDataForBlock(text);
+
+ handleContextChange(m_currentContext->lineBeginContext(),
+ m_currentContext->definition());
+
+ ProgressData progress;
+ const int length = text.length();
+ while (progress.offset() < length) {
+ if (progress.offset() > 0 &&
+ progress.onlySpacesSoFar() &&
+ !text.at(progress.offset()).isSpace()) {
+ progress.setOnlySpacesSoFar(false);
+ }
+
+ iterateThroughRules(text, length, &progress, false, m_currentContext->rules());
+ }
+
+ handleContextChange(m_currentContext->lineEndContext(),
+ m_currentContext->definition(),
+ false);
+ m_contexts.clear();
+ } catch (const HighlighterException &) {
+ m_isBroken = true;
+ }
+ }
+
+ applyVisualWhitespaceFormat(text);
+}
+
+void Highlighter::setupDataForBlock(const QString &text)
+{
+ if (currentBlockState() == WillContinue)
+ analyseConsistencyOfWillContinueBlock(text);
+
+ if (previousBlockState() == Default || previousBlockState() == -1)
+ setupDefault();
+ else if (previousBlockState() == WillContinue)
+ setupFromWillContinue();
+ else if (previousBlockState() == Continued)
+ setupFromContinued();
+ else
+ setupFromPersistent();
+
+ setCurrentContext();
+}
+
+void Highlighter::setupDefault()
+{
+ m_contexts.push_back(m_defaultContext);
+
+ setCurrentBlockState(Default);
+}
+
+void Highlighter::setupFromWillContinue()
+{
+ BlockData *previousData = static_cast<BlockData *>(currentBlock().previous().userData());
+ m_contexts.push_back(previousData->m_contextToContinue);
+
+ if (!currentBlockUserData()) {
+ BlockData *data = initializeBlockData();
+ data->m_originalState = previousData->m_originalState;
+ }
+
+ if (currentBlockState() == Default || currentBlockState() == -1)
+ setCurrentBlockState(Continued);
+}
+
+void Highlighter::setupFromContinued()
+{
+ BlockData *previousData = static_cast<BlockData *>(currentBlock().previous().userData());
+
+ Q_ASSERT(previousData->m_originalState != WillContinue &&
+ previousData->m_originalState != Continued);
+
+ if (previousData->m_originalState == Default || previousData->m_originalState == -1)
+ m_contexts.push_back(m_defaultContext);
+ else
+ pushContextSequence(previousData->m_originalState);
+
+ setCurrentBlockState(previousData->m_originalState);
+}
+
+void Highlighter::setupFromPersistent()
+{
+ pushContextSequence(previousBlockState());
+
+ setCurrentBlockState(previousBlockState());
+}
+
+void Highlighter::iterateThroughRules(const QString &text,
+ const int length,
+ ProgressData *progress,
+ const bool childRule,
+ const QList<QSharedPointer<Rule> > &rules)
+{
+ typedef QList<QSharedPointer<Rule> >::const_iterator RuleIterator;
+
+ bool contextChanged = false;
+ bool atLeastOneMatch = false;
+
+ RuleIterator it = rules.begin();
+ RuleIterator endIt = rules.end();
+ while (it != endIt && progress->offset() < length) {
+ int startOffset = progress->offset();
+
+ const QSharedPointer<Rule> &rule = *it;
+ if (rule->matchSucceed(text, length, progress)) {
+ atLeastOneMatch = true;
+
+ if (progress->willContinueLine()) {
+ createWillContinueBlock();
+ progress->setWillContinueLine(false);
+ } else {
+ if (rule->hasChild())
+ iterateThroughRules(text, length, progress, true, rule->childs());
+
+ if (!rule->context().isEmpty() && contextChangeRequired(rule->context())) {
+ m_currentCaptures = progress->captures();
+ changeContext(rule->context(), rule->definition());
+ contextChanged = true;
+ }
+ }
+
+ // Format is not applied to child rules directly (but relative to the offset of their
+ // parent) nor to look ahead rules.
+ if (!childRule && !rule->isLookAhead()) {
+ if (rule->itemData().isEmpty())
+ applyFormat(startOffset, progress->offset() - startOffset,
+ m_currentContext->itemData(), m_currentContext->definition());
+ else
+ applyFormat(startOffset, progress->offset() - startOffset, rule->itemData(),
+ rule->definition());
+ }
+
+ // When there is a match of one child rule the others should be skipped. Otherwise
+ // the highlighting would be incorret in a case like 9ULLLULLLUULLULLUL, for example.
+ if (contextChanged || childRule) {
+ break;
+ } else {
+ it = rules.begin();
+ continue;
+ }
+ }
+ ++it;
+ }
+
+ if (!childRule && !atLeastOneMatch) {
+ if (m_currentContext->isFallthrough()) {
+ handleContextChange(m_currentContext->fallthroughContext(),
+ m_currentContext->definition());
+ iterateThroughRules(text, length, progress, false, m_currentContext->rules());
+ } else {
+ applyFormat(progress->offset(), 1, m_currentContext->itemData(),
+ m_currentContext->definition());
+ progress->incrementOffset();
+ }
+ }
+}
+
+bool Highlighter::contextChangeRequired(const QString &contextName) const
+{
+ if (contextName == kStay)
+ return false;
+ return true;
+}
+
+void Highlighter::changeContext(const QString &contextName,
+ const QSharedPointer<HighlightDefinition> &definition,
+ const bool setCurrent)
+{
+ if (contextName.startsWith(kPop)) {
+ QStringList list = contextName.split(kHash, QString::SkipEmptyParts);
+ for (int i = 0; i < list.size(); ++i)
+ m_contexts.pop_back();
+
+ if (currentBlockState() >= PersistentsStart) {
+ // One or more contexts were popped during during a persistent state.
+ const QString ¤tSequence = currentContextSequence();
+ if (m_persistentStates.contains(currentSequence))
+ setCurrentBlockState(m_persistentStates.value(currentSequence));
+ else
+ setCurrentBlockState(m_leadingStates.value(currentSequence));
+ }
+ } else {
+ const QSharedPointer<Context> &context = definition->context(contextName);
+
+ if (context->isDynamic())
+ pushDynamicContext(context);
+ else
+ m_contexts.push_back(context);
+
+ if (m_contexts.back()->lineEndContext() == kStay ||
+ currentBlockState() >= PersistentsStart) {
+ const QString ¤tSequence = currentContextSequence();
+ mapLeadingSequence(currentSequence);
+ if (m_contexts.back()->lineEndContext() == kStay) {
+ // A persistent context was pushed.
+ mapPersistentSequence(currentSequence);
+ setCurrentBlockState(m_persistentStates.value(currentSequence));
+ }
+ }
+ }
+
+ if (setCurrent)
+ setCurrentContext();
+}
+
+void Highlighter::handleContextChange(const QString &contextName,
+ const QSharedPointer<HighlightDefinition> &definition,
+ const bool setCurrent)
+{
+ if (!contextName.isEmpty() && contextChangeRequired(contextName))
+ changeContext(contextName, definition, setCurrent);
+}
+
+void Highlighter::applyFormat(int offset,
+ int count,
+ const QString &itemDataName,
+ const QSharedPointer<HighlightDefinition> &definition)
+{
+ if (count == 0)
+ return;
+
+ QSharedPointer<ItemData> itemData;
+ try {
+ itemData = definition->itemData(itemDataName);
+ } catch (const HighlighterException &) {
+ // There are some broken files. For instance, the Printf context in java.xml points to an
+ // inexistent Printf item data. These cases are considered to have normal text style.
+ return;
+ }
+
+ TextFormatId formatId = m_kateFormats.m_ids.value(itemData->style());
+ if (formatId != Normal) {
+ QTextCharFormat format = m_creatorFormats.value(formatId);
+
+ if (itemData->isCustomized()) {
+ // Please notice that the following are applied every time for item datas which have
+ // customizations. The configureFormats method could be used to provide a "one time"
+ // configuration, but it would probably require to traverse all item datas from all
+ // definitions available/loaded (either to set the values or for some "notifying"
+ // strategy). This is because the highlighter does not really know on which
+ // definition(s) it is working. Since not many item datas specify customizations I
+ // think this approach would fit better. If there are other ideas...
+ if (itemData->color().isValid())
+ format.setForeground(itemData->color());
+ if (itemData->isItalicSpecified())
+ format.setFontItalic(itemData->isItalic());
+ if (itemData->isBoldSpecified())
+ format.setFontWeight(toFontWeight(itemData->isBold()));
+ if (itemData->isUnderlinedSpecified())
+ format.setFontUnderline(itemData->isUnderlined());
+ if (itemData->isStrikedOutSpecified())
+ format.setFontStrikeOut(itemData->isStrikedOut());
+ }
+
+ setFormat(offset, count, format);
+ }
+}
+
+void Highlighter::applyVisualWhitespaceFormat(const QString &text)
+{
+ int offset = 0;
+ const int length = text.length();
+ while (offset < length) {
+ if (text.at(offset).isSpace()) {
+ int start = offset++;
+ while (offset < length && text.at(offset).isSpace())
+ ++offset;
+ setFormat(start, offset - start, m_creatorFormats.value(VisualWhitespace));
+ } else {
+ ++offset;
+ }
+ }
+}
+
+void Highlighter::createWillContinueBlock()
+{
+ if (!currentBlockUserData())
+ initializeBlockData();
+
+ BlockData *data = static_cast<BlockData *>(currentBlockUserData());
+ if (currentBlockState() == Continued) {
+ BlockData *previousData = static_cast<BlockData *>(currentBlock().previous().userData());
+ data->m_originalState = previousData->m_originalState;
+ } else if (currentBlockState() != WillContinue) {
+ data->m_originalState = currentBlockState();
+ }
+ data->m_contextToContinue = m_currentContext;
+
+ setCurrentBlockState(WillContinue);
+}
+
+void Highlighter::analyseConsistencyOfWillContinueBlock(const QString &text)
+{
+ if (currentBlock().next().isValid() && (
+ text.length() == 0 || text.at(text.length() - 1) != kBackSlash) &&
+ currentBlock().next().userState() != Continued) {
+ currentBlock().next().setUserState(Continued);
+ }
+
+ if (text.length() == 0 || text.at(text.length() - 1) != kBackSlash) {
+ BlockData *data = static_cast<BlockData *>(currentBlockUserData());
+ data->m_contextToContinue.clear();
+ setCurrentBlockState(data->m_originalState);
+ }
+}
+
+void Highlighter::mapPersistentSequence(const QString &contextSequence)
+{
+ if (!m_persistentStates.contains(contextSequence)) {
+ int newState = m_persistentStatesCounter;
+ m_persistentStates.insert(contextSequence, newState);
+ m_persistentContexts.insert(newState, m_contexts);
+ ++m_persistentStatesCounter;
+ }
+}
+
+void Highlighter::mapLeadingSequence(const QString &contextSequence)
+{
+ if (!m_leadingStates.contains(contextSequence))
+ m_leadingStates.insert(contextSequence, currentBlockState());
+}
+
+void Highlighter::pushContextSequence(int state)
+{
+ const QVector<QSharedPointer<Context> > &contexts = m_persistentContexts.value(state);
+ for (int i = 0; i < contexts.size(); ++i)
+ m_contexts.push_back(contexts.at(i));
+}
+
+QString Highlighter::currentContextSequence() const
+{
+ QString sequence;
+ for (int i = 0; i < m_contexts.size(); ++i)
+ sequence.append(m_contexts.at(i)->id());
+
+ return sequence;
+}
+
+Highlighter::BlockData *Highlighter::initializeBlockData()
+{
+ BlockData *data = new BlockData;
+ setCurrentBlockUserData(data);
+ return data;
+}
+
+void Highlighter::pushDynamicContext(const QSharedPointer<Context> &baseContext)
+{
+ // A dynamic context is created from another context which serves as its basis. Then,
+ // its rules are updated according to the captures from the calling regular expression which
+ // triggered the push of the dynamic context.
+ QSharedPointer<Context> context(new Context(*baseContext));
+ context->configureId(m_dynamicContextsCounter);
+ context->updateDynamicRules(m_currentCaptures);
+ m_contexts.push_back(context);
+ ++m_dynamicContextsCounter;
+}
+
+void Highlighter::setCurrentContext()
+{
+ if (m_contexts.isEmpty()) {
+ // This is not supposed to happen. However, there are broken files (for example, php.xml)
+ // which will cause this behaviour. In such cases pushing the default context is enough to
+ // keep highlighter working.
+ m_contexts.push_back(m_defaultContext);
+ }
+ m_currentContext = m_contexts.back();
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTER_H
+#define HIGHLIGHTER_H
+
+#include "basetextdocumentlayout.h"
+
+#include <QtCore/QString>
+#include <QtCore/QVector>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QStringList>
+
+#include <QtGui/QSyntaxHighlighter>
+#include <QtGui/QTextCharFormat>
+
+namespace TextEditor {
+namespace Internal {
+
+class Rule;
+class Context;
+class HighlightDefinition;
+class ProgressData;
+
+class Highlighter : public QSyntaxHighlighter
+{
+public:
+ Highlighter(QTextDocument *parent = 0);
+ virtual ~Highlighter();
+
+ enum TextFormatId {
+ Normal,
+ VisualWhitespace,
+ Keyword,
+ DataType,
+ Decimal,
+ BaseN,
+ Float,
+ Char,
+ String,
+ Comment,
+ Alert,
+ Error,
+ Function,
+ RegionMarker,
+ Others
+ };
+ void configureFormat(TextFormatId id, const QTextCharFormat &format);
+
+ void setDefaultContext(const QSharedPointer<Context> &defaultContext);
+
+protected:
+ virtual void highlightBlock(const QString &text);
+
+private:
+
+ void setupDataForBlock(const QString &text);
+ void setupDefault();
+ void setupFromWillContinue();
+ void setupFromContinued();
+ void setupFromPersistent();
+
+ void iterateThroughRules(const QString &text,
+ const int length,
+ ProgressData *progress,
+ const bool childRule,
+ const QList<QSharedPointer<Rule> > &rules);
+
+ void setCurrentContext();
+ bool contextChangeRequired(const QString &contextName) const;
+ void handleContextChange(const QString &contextName,
+ const QSharedPointer<HighlightDefinition> &definition,
+ const bool setCurrent = true);
+ void changeContext(const QString &contextName,
+ const QSharedPointer<HighlightDefinition> &definition,
+ const bool setCurrent = true);
+
+ QString currentContextSequence() const;
+ void mapPersistentSequence(const QString &contextSequence);
+ void mapLeadingSequence(const QString &contextSequence);
+ void pushContextSequence(int state);
+
+ void pushDynamicContext(const QSharedPointer<Context> &baseContext);
+
+ void createWillContinueBlock();
+ void analyseConsistencyOfWillContinueBlock(const QString &text);
+
+ void applyFormat(int offset,
+ int count,
+ const QString &itemDataName,
+ const QSharedPointer<HighlightDefinition> &definition);
+ void applyVisualWhitespaceFormat(const QString &text);
+
+ // Mapping from Kate format strings to format ids.
+ struct KateFormatMap
+ {
+ KateFormatMap();
+ QHash<QString, TextFormatId> m_ids;
+ };
+ static const KateFormatMap m_kateFormats;
+ QHash<TextFormatId, QTextCharFormat> m_creatorFormats;
+
+ struct BlockData : TextBlockUserData
+ {
+ BlockData();
+ virtual ~BlockData();
+
+ int m_originalState;
+ QSharedPointer<Context> m_contextToContinue;
+ };
+ BlockData *initializeBlockData();
+
+ // Block states
+ // - Default [0]: Nothing special.
+ // - WillContinue [1]: When there is match of the LineContinue rule (backslash as the last
+ // character).
+ // - Continued [2]: Blocks that happen after a WillContinue block and continued from their
+ // context until the next line end.
+ // - Persistent(s) [Anything >= 3]: Correspond to persistent contexts which last until a pop
+ // occurs due to a matching rule. Every sequence of persistent contexts seen so far is
+ // associated with a number (incremented by a unit each time).
+ enum BlockState {
+ Default = 0,
+ WillContinue,
+ Continued,
+ PersistentsStart
+ };
+ int m_persistentStatesCounter;
+ int m_dynamicContextsCounter;
+
+ bool m_isBroken;
+
+ QSharedPointer<Context> m_defaultContext;
+ QSharedPointer<Context> m_currentContext;
+ QVector<QSharedPointer<Context> > m_contexts;
+
+ // Mapping from context sequences to the persistent state they represent.
+ QHash<QString, int> m_persistentStates;
+ // Mapping from context sequences to the non-persistent state that led to them.
+ QHash<QString, int> m_leadingStates;
+ // Mapping from persistent states to context sequences (the actual "stack").
+ QHash<int, QVector<QSharedPointer<Context> > > m_persistentContexts;
+
+ // Captures used in dynamic rules.
+ QStringList m_currentCaptures;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // HIGHLIGHTER_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTEREXCEPTION_H
+#define HIGHLIGHTEREXCEPTION_H
+
+namespace TextEditor {
+namespace Internal {
+
+class HighlighterException {};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // HIGHLIGHTEREXCEPTION_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlightersettings.h"
+
+#include <coreplugin/icore.h>
+
+#include <QtCore/QSettings>
+#include <QtCore/QLatin1String>
+#include <QtCore/QLatin1Char>
+#include <QtCore/QDebug>
+#ifdef Q_OS_UNIX
+#include <QtCore/QDir>
+#include <QtCore/QProcess>
+#endif
+
+namespace TextEditor {
+namespace Internal {
+
+QString findDefinitionsLocation()
+{
+ QString definitionsLocation;
+
+#ifdef Q_OS_UNIX
+ static const QLatin1String kateSyntax("/share/apps/katepart/syntax");
+
+ // Some wild guesses.
+ QDir dir;
+ QStringList paths;
+ paths << QLatin1String("/usr") + kateSyntax
+ << QLatin1String("/usr/local") + kateSyntax
+ << QLatin1String("/opt") + kateSyntax;
+ foreach (const QString &path, paths) {
+ dir.setPath(path);
+ if (dir.exists()) {
+ definitionsLocation = path;
+ break;
+ }
+ }
+
+ if (definitionsLocation.isEmpty()) {
+ // Try kde-config.
+ QProcess process;
+ process.start(QLatin1String("kde-config"), QStringList(QLatin1String("--prefix")));
+ if (process.waitForStarted(5000)) {
+ process.waitForFinished(5000);
+ QString output = QString::fromLocal8Bit(process.readAllStandardOutput());
+ output.remove(QLatin1Char('\n'));
+ dir.setPath(output + kateSyntax);
+ if (dir.exists())
+ definitionsLocation = dir.path();
+ }
+ }
+#endif
+
+ if (definitionsLocation.isEmpty())
+ definitionsLocation = Core::ICore::instance()->resourcePath() +
+ QLatin1String("/generic-highlighter");
+
+ return definitionsLocation;
+}
+
+} // namespace Internal
+} // namespace TextEditor
+
+namespace {
+
+static const QLatin1String kDefinitionFilesPath("DefinitionFilesPath");
+static const QLatin1String kAlertWhenDefinitionIsNotFound("AlertWhenDefinitionsIsNotFound");
+static const QLatin1String kIgnoredFilesPatterns("IgnoredFilesPatterns");
+static const QLatin1String kGroupPostfix("HighlighterSettings");
+
+QString groupSpecifier(const QString &postFix, const QString &category)
+{
+ if (category.isEmpty())
+ return postFix;
+ return QString(category + postFix);
+}
+
+} // namespace anonymous
+
+using namespace TextEditor;
+using namespace Internal;
+
+HighlighterSettings::HighlighterSettings() : m_alertWhenNoDefinition(true)
+{}
+
+void HighlighterSettings::toSettings(const QString &category, QSettings *s) const
+{
+ const QString &group = groupSpecifier(kGroupPostfix, category);
+ s->beginGroup(group);
+ s->setValue(kDefinitionFilesPath, m_definitionFilesPath);
+ s->setValue(kAlertWhenDefinitionIsNotFound, m_alertWhenNoDefinition);
+ s->setValue(kIgnoredFilesPatterns, ignoredFilesPatterns());
+ s->endGroup();
+}
+
+void HighlighterSettings::fromSettings(const QString &category, QSettings *s)
+{
+ const QString &group = groupSpecifier(kGroupPostfix, category);
+ s->beginGroup(group);
+ if (!s->contains(kDefinitionFilesPath))
+ m_definitionFilesPath = findDefinitionsLocation();
+ else
+ m_definitionFilesPath = s->value(kDefinitionFilesPath, QString()).toString();
+ m_alertWhenNoDefinition = s->value(kAlertWhenDefinitionIsNotFound, true).toBool();
+ if (!s->contains(kIgnoredFilesPatterns))
+ assignInitialIgnoredPatterns();
+ else
+ setIgnoredFilesPatterns(s->value(kIgnoredFilesPatterns, QString()).toString());
+ s->endGroup();
+}
+
+void HighlighterSettings::setIgnoredFilesPatterns(const QString &patterns)
+{
+ setExpressionsFromList(patterns.split(QLatin1Char(','), QString::SkipEmptyParts));
+}
+
+QString HighlighterSettings::ignoredFilesPatterns() const
+{
+ return listFromExpressions().join(QLatin1String(","));
+}
+
+void HighlighterSettings::assignInitialIgnoredPatterns()
+{
+ QStringList patterns;
+ patterns << QLatin1String("*.txt")
+ << QLatin1String("LICENSE*")
+ << QLatin1String("README")
+ << QLatin1String("INSTALL")
+ << QLatin1String("COPYING")
+ << QLatin1String("NEWS");
+ setExpressionsFromList(patterns);
+}
+
+bool HighlighterSettings::isIgnoredFilePattern(const QString &fileName) const
+{
+ foreach (const QRegExp ®Exp, m_ignoredFiles)
+ if (regExp.indexIn(fileName) != -1)
+ return true;
+
+ return false;
+}
+
+bool HighlighterSettings::equals(const HighlighterSettings &highlighterSettings) const
+{
+ return m_definitionFilesPath == highlighterSettings.m_definitionFilesPath &&
+ m_alertWhenNoDefinition == highlighterSettings.m_alertWhenNoDefinition &&
+ m_ignoredFiles == highlighterSettings.m_ignoredFiles;
+}
+
+void HighlighterSettings::setExpressionsFromList(const QStringList &patterns)
+{
+ m_ignoredFiles.clear();
+ QRegExp regExp;
+ regExp.setCaseSensitivity(Qt::CaseInsensitive);
+ regExp.setPatternSyntax(QRegExp::Wildcard);
+ foreach (const QString &s, patterns) {
+ regExp.setPattern(s);
+ m_ignoredFiles.append(regExp);
+ }
+}
+
+QStringList HighlighterSettings::listFromExpressions() const
+{
+ QStringList patterns;
+ foreach (const QRegExp ®Exp, m_ignoredFiles)
+ patterns.append(regExp.pattern());
+ return patterns;
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTERSETTINGS_H
+#define HIGHLIGHTERSETTINGS_H
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QList>
+#include <QtCore/QRegExp>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+class HighlighterSettings
+{
+public:
+ HighlighterSettings();
+
+ void toSettings(const QString &category, QSettings *s) const;
+ void fromSettings(const QString &category, QSettings *s);
+
+ void setDefinitionFilesPath(const QString &path) { m_definitionFilesPath = path; }
+ const QString &definitionFilesPath() const { return m_definitionFilesPath; }
+
+ void setAlertWhenNoDefinition(const bool alert) { m_alertWhenNoDefinition = alert; }
+ bool alertWhenNoDefinition() const { return m_alertWhenNoDefinition; }
+
+ void setIgnoredFilesPatterns(const QString &patterns);
+ QString ignoredFilesPatterns() const;
+ bool isIgnoredFilePattern(const QString &fileName) const;
+
+ bool equals(const HighlighterSettings &highlighterSettings) const;
+
+private:
+ void assignInitialIgnoredPatterns();
+
+ void setExpressionsFromList(const QStringList &patterns);
+ QStringList listFromExpressions() const;
+
+ bool m_alertWhenNoDefinition;
+ QString m_definitionFilesPath;
+ QList<QRegExp> m_ignoredFiles;
+};
+
+inline bool operator==(const HighlighterSettings &a, const HighlighterSettings &b)
+{ return a.equals(b); }
+
+inline bool operator!=(const HighlighterSettings &a, const HighlighterSettings &b)
+{ return !a.equals(b); }
+
+namespace Internal {
+QString findDefinitionsLocation();
+}
+
+} // namespace TextEditor
+
+#endif // HIGHLIGHTERSETTINGS_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlightersettingspage.h"
+#include "highlightersettings.h"
+#include "manager.h"
+#include "managedefinitionsdialog.h"
+#include "ui_highlightersettingspage.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+
+#include <QtGui/QMessageBox>
+
+using namespace TextEditor;
+using namespace Internal;
+
+struct HighlighterSettingsPage::HighlighterSettingsPagePrivate
+{
+ explicit HighlighterSettingsPagePrivate(const QString &id);
+
+ const QString m_id;
+ const QString m_displayName;
+ const QString m_settingsPrefix;
+
+ QString m_searchKeywords;
+
+ HighlighterSettings m_settings;
+
+ Ui::HighlighterSettingsPage m_page;
+};
+
+HighlighterSettingsPage::HighlighterSettingsPagePrivate::
+HighlighterSettingsPagePrivate(const QString &id) :
+ m_id(id),
+ m_displayName(tr("Generic Highlighter")),
+ m_settingsPrefix(QLatin1String("text"))
+{}
+
+HighlighterSettingsPage::HighlighterSettingsPage(const QString &id, QObject *parent) :
+ TextEditorOptionsPage(parent),
+ m_d(new HighlighterSettingsPagePrivate(id))
+{
+ if (QSettings *s = Core::ICore::instance()->settings())
+ m_d->m_settings.fromSettings(m_d->m_settingsPrefix, s);
+
+ connect(this, SIGNAL(definitionsLocationChanged()),
+ Manager::instance(), SLOT(registerMimeTypes()));
+}
+
+HighlighterSettingsPage::~HighlighterSettingsPage()
+{
+ delete m_d;
+}
+
+QString HighlighterSettingsPage::id() const
+{
+ return m_d->m_id;
+}
+
+QString HighlighterSettingsPage::displayName() const
+{
+ return m_d->m_displayName;
+}
+
+QWidget *HighlighterSettingsPage::createPage(QWidget *parent)
+{
+ QWidget *w = new QWidget(parent);
+ m_d->m_page.setupUi(w);
+ m_d->m_page.definitionFilesPath->setExpectedKind(Utils::PathChooser::Directory);
+
+ settingsToUI();
+
+ if (m_d->m_searchKeywords.isEmpty()) {
+ QTextStream(&m_d->m_searchKeywords) << m_d->m_page.definitionFilesGroupBox->title()
+ << m_d->m_page.locationLabel->text()
+ << m_d->m_page.alertWhenNoDefinition->text()
+ << m_d->m_page.ignoreLabel->text();
+ }
+
+ connect(m_d->m_page.resetButton, SIGNAL(clicked()), this, SLOT(resetDefinitionsLocation()));
+ connect(m_d->m_page.manageDefinitionsButton, SIGNAL(clicked()),
+ this, SLOT(requestAvailableDefinitionsMetaData()));
+ connect(w, SIGNAL(destroyed()), this, SLOT(ignoreDownloadReply()));
+
+ return w;
+}
+
+void HighlighterSettingsPage::apply()
+{
+ if (settingsChanged())
+ settingsFromUI();
+}
+
+bool HighlighterSettingsPage::matches(const QString &s) const
+{
+ return m_d->m_searchKeywords.contains(s, Qt::CaseInsensitive);
+}
+
+const HighlighterSettings &HighlighterSettingsPage::highlighterSettings() const
+{
+ return m_d->m_settings;
+}
+
+void HighlighterSettingsPage::settingsFromUI()
+{
+ bool locationChanged = false;
+ if (m_d->m_settings.definitionFilesPath() != m_d->m_page.definitionFilesPath->path())
+ locationChanged = true;
+
+ m_d->m_settings.setDefinitionFilesPath(m_d->m_page.definitionFilesPath->path());
+ m_d->m_settings.setAlertWhenNoDefinition(m_d->m_page.alertWhenNoDefinition->isChecked());
+ m_d->m_settings.setIgnoredFilesPatterns(m_d->m_page.ignoreEdit->text());
+ if (QSettings *s = Core::ICore::instance()->settings())
+ m_d->m_settings.toSettings(m_d->m_settingsPrefix, s);
+
+ if (locationChanged)
+ emit definitionsLocationChanged();
+}
+
+void HighlighterSettingsPage::settingsToUI()
+{
+ m_d->m_page.definitionFilesPath->setPath(m_d->m_settings.definitionFilesPath());
+ m_d->m_page.alertWhenNoDefinition->setChecked(m_d->m_settings.alertWhenNoDefinition());
+ m_d->m_page.ignoreEdit->setText(m_d->m_settings.ignoredFilesPatterns());
+}
+
+void HighlighterSettingsPage::resetDefinitionsLocation()
+{
+ m_d->m_page.definitionFilesPath->setPath(findDefinitionsLocation());
+}
+
+void HighlighterSettingsPage::requestAvailableDefinitionsMetaData()
+{
+ m_d->m_page.manageDefinitionsButton->setEnabled(false);
+
+ Manager::instance()->downloadAvailableDefinitionsMetaData();
+ connect(Manager::instance(),
+ SIGNAL(definitionsMetaDataReady(QList<Internal::HighlightDefinitionMetaData>)),
+ this,
+ SLOT(manageDefinitions(QList<Internal::HighlightDefinitionMetaData>)),
+ Qt::UniqueConnection);
+ connect(Manager::instance(), SIGNAL(errorDownloadingDefinitionsMetaData()),
+ this, SLOT(showError()), Qt::UniqueConnection);
+}
+
+void HighlighterSettingsPage::ignoreDownloadReply()
+{
+ disconnect(Manager::instance(),
+ SIGNAL(definitionsMetaDataReady(QList<Internal::HighlightDefinitionMetaData>)),
+ this,
+ SLOT(manageDefinitions(QList<Internal::HighlightDefinitionMetaData>)));
+ disconnect(Manager::instance(), SIGNAL(errorDownloadingDefinitionsMetaData()),
+ this, SLOT(showError()));
+}
+
+void HighlighterSettingsPage::manageDefinitions(const QList<HighlightDefinitionMetaData> &metaData)
+{
+ ManageDefinitionsDialog dialog(metaData, m_d->m_page.manageDefinitionsButton->window());
+ dialog.exec();
+ m_d->m_page.manageDefinitionsButton->setEnabled(true);
+}
+
+void HighlighterSettingsPage::showError()
+{
+ QMessageBox::critical(m_d->m_page.manageDefinitionsButton->window(),
+ tr("Error connecting to server."),
+ tr("Not possible to retrieve data."));
+ m_d->m_page.manageDefinitionsButton->setEnabled(true);
+}
+
+bool HighlighterSettingsPage::settingsChanged() const
+{
+ if (m_d->m_settings.definitionFilesPath() != m_d->m_page.definitionFilesPath->path())
+ return true;
+ if (m_d->m_settings.alertWhenNoDefinition() != m_d->m_page.alertWhenNoDefinition->isChecked())
+ return true;
+ if (m_d->m_settings.ignoredFilesPatterns() != m_d->m_page.ignoreEdit->text())
+ return true;
+ return false;
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTERSETTINGSPAGE_H
+#define HIGHLIGHTERSETTINGSPAGE_H
+
+#include "texteditoroptionspage.h"
+
+QT_BEGIN_NAMESPACE
+template <class> class QList;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+namespace Internal {
+class HighlightDefinitionMetaData;
+}
+
+class HighlighterSettings;
+
+class HighlighterSettingsPage : public TextEditorOptionsPage
+{
+ Q_OBJECT
+public:
+ HighlighterSettingsPage(const QString &id, QObject *parent);
+ virtual ~HighlighterSettingsPage();
+
+ QString id() const;
+ QString displayName() const;
+
+ QWidget *createPage(QWidget *parent);
+ void apply();
+ void finish() {}
+ bool matches(const QString &s) const;
+
+ const HighlighterSettings &highlighterSettings() const;
+
+signals:
+ void definitionsLocationChanged();
+
+private slots:
+ void resetDefinitionsLocation();
+ void requestAvailableDefinitionsMetaData();
+ void manageDefinitions(const QList<Internal::HighlightDefinitionMetaData> &metaData);
+ void showError();
+ void ignoreDownloadReply();
+
+private:
+ void settingsFromUI();
+ void settingsToUI();
+
+ bool settingsChanged() const;
+
+ struct HighlighterSettingsPagePrivate;
+ HighlighterSettingsPagePrivate *m_d;
+};
+
+} // namespace TextEditor
+
+#endif // HIGHLIGHTERSETTINGSPAGE_H
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>HighlighterSettingsPage</class>
+ <widget class="QWidget" name="HighlighterSettingsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>521</width>
+ <height>332</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QGroupBox" name="definitionFilesGroupBox">
+ <property name="title">
+ <string>Syntax Highlight Definition Files</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="locationLabel">
+ <property name="text">
+ <string>Location:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Utils::PathChooser" name="definitionFilesPath" native="true"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QToolButton" name="resetButton">
+ <property name="toolTip">
+ <string>Reset to default</string>
+ </property>
+ <property name="text">
+ <string>R</string>
+ </property>
+ <property name="icon">
+ <iconset resource="../../coreplugin/core.qrc">
+ <normaloff>:/core/images/reset.png</normaloff>:/core/images/reset.png</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="definitionsInfolabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Highlight definitions are available from the </span><a href="http://kate-editor.org/downloads/syntax_highlighting?kateversion=3.2"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">Kate Text Editor</span></a><span style=" font-size:8pt;"> website. Qt Creator can download a list of available definitions and then install the selected ones.</span></p></body></html></string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::RichText</enum>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QPushButton" name="manageDefinitionsButton">
+ <property name="text">
+ <string>Manage Definitions</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>328</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="behaviorGroupBox">
+ <property name="title">
+ <string>Behavior</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="alertWhenNoDefinition">
+ <property name="text">
+ <string>Alert when a highlight definition is not found</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="ignoreLabel">
+ <property name="text">
+ <string>Ignored file patterns:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="ignoreEdit"/>
+ </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>146</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Utils::PathChooser</class>
+ <extends>QWidget</extends>
+ <header location="global">utils/pathchooser.h</header>
+ <container>1</container>
+ <slots>
+ <signal>editingFinished()</signal>
+ <signal>browsingFinished()</signal>
+ </slots>
+ </customwidget>
+ </customwidgets>
+ <tabstops>
+ <tabstop>resetButton</tabstop>
+ <tabstop>manageDefinitionsButton</tabstop>
+ <tabstop>alertWhenNoDefinition</tabstop>
+ <tabstop>ignoreEdit</tabstop>
+ </tabstops>
+ <resources>
+ <include location="../../coreplugin/core.qrc"/>
+ </resources>
+ <connections/>
+</ui>
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "includerulesinstruction.h"
+#include "reuse.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+IncludeRulesInstruction::IncludeRulesInstruction(const QString &context,
+ int hint,
+ const QString &replaceItemData) :
+ m_sourceContext(context), m_indexHint(hint), m_replaceItemData(toBool(replaceItemData))
+{
+}
+
+const QString &IncludeRulesInstruction::sourceContext() const
+{ return m_sourceContext; }
+
+int IncludeRulesInstruction::indexHint() const
+{ return m_indexHint; }
+
+bool IncludeRulesInstruction::replaceItemData() const
+{ return m_replaceItemData; }
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef INCLUDERULESINSTRUCTION_H
+#define INCLUDERULESINSTRUCTION_H
+
+#include <QtCore/QString>
+
+namespace TextEditor {
+namespace Internal {
+
+class IncludeRulesInstruction
+{
+public:
+ IncludeRulesInstruction(const QString &context, int hint, const QString &replaceItemData);
+
+ const QString &sourceContext() const;
+ int indexHint() const;
+ bool replaceItemData() const;
+
+private:
+ QString m_sourceContext;
+ int m_indexHint;
+ bool m_replaceItemData;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // INCLUDERULESINSTRUCTION_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "itemdata.h"
+#include "reuse.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+ItemData::ItemData() :
+ m_italicSpecified(false),
+ m_boldSpecified(false),
+ m_underlinedSpecified(false),
+ m_strikedOutSpecified(false),
+ m_isCustomized(false)
+{}
+
+void ItemData::setStyle(const QString &style)
+{ m_style = style; }
+
+const QString &ItemData::style() const
+{ return m_style; }
+
+void ItemData::setColor(const QString &color)
+{
+ if (!color.isEmpty()) {
+ m_color.setNamedColor(color);
+ m_isCustomized = true;
+ }
+}
+
+const QColor &ItemData::color() const
+{ return m_color; }
+
+void ItemData::setSelectionColor(const QString &color)
+{
+ if (!color.isEmpty()) {
+ m_selectionColor.setNamedColor(color);
+ m_isCustomized = true;
+ }
+}
+
+const QColor &ItemData::selectionColor() const
+{ return m_selectionColor; }
+
+void ItemData::setItalic(const QString &italic)
+{
+ if (!italic.isEmpty()) {
+ m_italic = toBool(italic);
+ m_italicSpecified = true;
+ m_isCustomized = true;
+ }
+}
+
+bool ItemData::isItalic() const
+{ return m_italic; }
+
+bool ItemData::isItalicSpecified() const
+{ return m_italicSpecified; }
+
+void ItemData::setBold(const QString &bold)
+{
+ if (!bold.isEmpty()) {
+ m_bold = toBool(bold);
+ m_boldSpecified = true;
+ m_isCustomized = true;
+ }
+}
+
+bool ItemData::isBold() const
+{ return m_bold; }
+
+bool ItemData::isBoldSpecified() const
+{ return m_boldSpecified; }
+
+void ItemData::setUnderlined(const QString &underlined)
+{
+ if (!underlined.isEmpty()) {
+ m_underlined = toBool(underlined);
+ m_underlinedSpecified = true;
+ m_isCustomized = true;
+ }
+}
+
+bool ItemData::isUnderlined() const
+{ return m_underlined; }
+
+bool ItemData::isUnderlinedSpecified() const
+{ return m_underlinedSpecified; }
+
+void ItemData::setStrikedOut(const QString &striked)
+{
+ if (!striked.isEmpty()) {
+ m_strikedOut = toBool(striked);
+ m_strikedOutSpecified = true;
+ m_isCustomized = true;
+ }
+}
+
+bool ItemData::isStrikedOut() const
+{ return m_strikedOut; }
+
+bool ItemData::isStrikedOutSpecified() const
+{ return m_strikedOutSpecified; }
+
+bool ItemData::isCustomized() const
+{ return m_isCustomized; }
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ITEMDATA_H
+#define ITEMDATA_H
+
+#include <QtCore/QString>
+#include <QtGui/QColor>
+
+namespace TextEditor {
+namespace Internal {
+
+class ItemData
+{
+public:
+ ItemData();
+
+ void setStyle(const QString &style);
+ const QString &style() const;
+
+ void setColor(const QString &color);
+ const QColor &color() const;
+
+ void setSelectionColor(const QString &color);
+ const QColor &selectionColor() const;
+
+ void setItalic(const QString &italic);
+ bool isItalic() const;
+ bool isItalicSpecified() const;
+
+ void setBold(const QString &bold);
+ bool isBold() const;
+ bool isBoldSpecified() const;
+
+ void setUnderlined(const QString &underlined);
+ bool isUnderlined() const;
+ bool isUnderlinedSpecified() const;
+
+ void setStrikedOut(const QString &striked);
+ bool isStrikedOut() const;
+ bool isStrikedOutSpecified() const;
+
+ bool isCustomized() const;
+
+private:
+ QString m_style;
+ QColor m_color;
+ QColor m_selectionColor;
+ bool m_italic;
+ bool m_italicSpecified;
+ bool m_bold;
+ bool m_boldSpecified;
+ bool m_underlined;
+ bool m_underlinedSpecified;
+ bool m_strikedOut;
+ bool m_strikedOutSpecified;
+ bool m_isCustomized;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // ITEMDATA_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "keywordlist.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+void KeywordList::addKeyword(const QString &keyword)
+{
+ if (keyword.isEmpty())
+ return;
+
+ m_keywords.insert(keyword);
+}
+
+bool KeywordList::isKeyword(const QString &keyword, Qt::CaseSensitivity sensitivity) const
+{
+ if (keyword.isEmpty())
+ return false;
+
+ // Case sensitivity could be implemented, for example, by converting all keywords to lower
+ // if the global sensitivity attribute is insensitive, then always checking for containment
+ // (with a conversion to lower in the necessary cases). But the code below is one alternative
+ // to support the existence of local sensitivity attributes (which override the global one -
+ // currently not documented).
+ if (sensitivity == Qt::CaseSensitive) {
+ return m_keywords.contains(keyword);
+ } else {
+ foreach (const QString &s, m_keywords)
+ if (keyword.compare(s, Qt::CaseInsensitive) == 0)
+ return true;
+ return false;
+ }
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef KEYWORDLIST_H
+#define KEYWORDLIST_H
+
+#include <QtCore/QString>
+#include <QtCore/QSet>
+
+namespace TextEditor {
+namespace Internal {
+
+class KeywordList
+{
+public:
+
+ void addKeyword(const QString &keyword);
+ bool isKeyword(const QString &keyword, Qt::CaseSensitivity sensitivity) const;
+
+private:
+ QSet<QString> m_keywords;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // KEYWORDLIST_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "managedefinitionsdialog.h"
+#include "manager.h"
+
+#include <QtCore>
+#include <QtCore/QUrl>
+#include <QtCore/QIODevice>
+#include <QtCore/QXmlStreamReader>
+#include <QtCore/QXmlStreamAttributes>
+#include <QtCore/QFuture>
+#include <QtCore/QFutureWatcher>
+#include <QtCore/QtConcurrentMap>
+#include <QtGui/QMessageBox>
+
+#include <QDebug>
+
+using namespace TextEditor;
+using namespace Internal;
+
+ManageDefinitionsDialog::ManageDefinitionsDialog(
+ const QList<HighlightDefinitionMetaData> &metaDataList, QWidget *parent) :
+ QDialog(parent), m_definitionsMetaData(metaDataList)
+{
+ ui.setupUi(this);
+ ui.definitionsTable->setHorizontalHeaderLabels(
+ QStringList() << tr("Definition Name") << tr("Installed") << tr("Available"));
+ ui.definitionsTable->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch);
+
+ setWindowTitle(tr("Manage Definitions"));
+
+ populateDefinitionsWidget();
+
+ connect(ui.downloadButton, SIGNAL(clicked()), this, SLOT(downloadDefinitions()));
+}
+
+void ManageDefinitionsDialog::populateDefinitionsWidget()
+{
+ const int size = m_definitionsMetaData.size();
+ ui.definitionsTable->setRowCount(size);
+ for (int i = 0; i < size; ++i) {
+ const HighlightDefinitionMetaData &downloadData = m_definitionsMetaData.at(i);
+
+ QString installedVersion;
+ const QString &id = Manager::instance()->definitionIdByName(downloadData.name());
+ const QSharedPointer<HighlightDefinitionMetaData> &metaData =
+ Manager::instance()->definitionMetaData(id);
+ if (!metaData.isNull())
+ installedVersion = metaData->version();
+
+ for (int j = 0; j < 3; ++j) {
+ QTableWidgetItem *item = new QTableWidgetItem;
+ if (j == 0)
+ item->setText(downloadData.name());
+ else if (j == 1) {
+ item->setText(installedVersion);
+ item->setTextAlignment(Qt::AlignCenter);
+ } else if (j == 2) {
+ item->setText(downloadData.version());
+ item->setTextAlignment(Qt::AlignCenter);
+ }
+ ui.definitionsTable->setItem(i, j, item);
+ }
+ }
+}
+
+void ManageDefinitionsDialog::downloadDefinitions()
+{
+ if (Manager::instance()->isDownloadingDefinitions()) {
+ QMessageBox::information(
+ this,
+ tr("Download Information"),
+ tr("There is already one download in progress. Please wait until it is finished."));
+ return;
+ }
+
+ QList<QUrl> urls;
+ foreach (const QModelIndex &index, ui.definitionsTable->selectionModel()->selectedRows())
+ urls.append(m_definitionsMetaData.at(index.row()).url());
+ Manager::instance()->downloadDefinitions(urls);
+ close();
+}
+
+void ManageDefinitionsDialog::changeEvent(QEvent *e)
+{
+ QDialog::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ ui.retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef MANAGEDEFINITIONSDIALOG_H
+#define MANAGEDEFINITIONSDIALOG_H
+
+#include "ui_managedefinitionsdialog.h"
+#include "highlightdefinitionmetadata.h"
+
+#include <QtCore/QList>
+
+namespace TextEditor {
+namespace Internal {
+
+class ManageDefinitionsDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ explicit ManageDefinitionsDialog(const QList<HighlightDefinitionMetaData> &metaDataList,
+ QWidget *parent = 0);
+
+protected:
+ void changeEvent(QEvent *e);
+
+private slots:
+ void downloadDefinitions();
+
+private:
+ void populateDefinitionsWidget();
+
+ QList<HighlightDefinitionMetaData> m_definitionsMetaData;
+ Ui::ManageDefinitionsDialog ui;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // MANAGEDEFINITIONSDIALOG_H
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ManageDefinitionsDialog</class>
+ <widget class="QDialog" name="ManageDefinitionsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>447</width>
+ <height>315</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QGroupBox" name="definitionsGroupBox">
+ <property name="title">
+ <string>Available Definitions</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTableWidget" name="definitionsTable">
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="columnCount">
+ <number>3</number>
+ </property>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="verticalHeaderDefaultSectionSize">
+ <number>20</number>
+ </attribute>
+ <column/>
+ <column/>
+ <column/>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="downloadButton">
+ <property name="text">
+ <string>Download Selected Definitions</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>188</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>298</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closeButton">
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>closeButton</sender>
+ <signal>clicked()</signal>
+ <receiver>ManageDefinitionsDialog</receiver>
+ <slot>close()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>381</x>
+ <y>294</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>306</x>
+ <y>298</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "manager.h"
+#include "highlightdefinition.h"
+#include "highlightdefinitionhandler.h"
+#include "highlighterexception.h"
+#include "definitiondownloader.h"
+#include "highlightersettings.h"
+#include "plaintexteditorfactory.h"
+#include "texteditorconstants.h"
+#include "texteditorplugin.h"
+#include "texteditorsettings.h"
+
+#include <coreplugin/icore.h>
+#include <utils/qtcassert.h>
+#include <coreplugin/progressmanager/progressmanager.h>
+#include <qtconcurrent/QtConcurrentTools>
+
+#include <QtCore/QtAlgorithms>
+#include <QtCore/QtPlugin>
+#include <QtCore/QString>
+#include <QtCore/QLatin1Char>
+#include <QtCore/QLatin1String>
+#include <QtCore/QStringList>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QRegExp>
+#include <QtCore/QFuture>
+#include <QtCore/QtConcurrentRun>
+#include <QtCore/QtConcurrentMap>
+#include <QtCore/QUrl>
+#include <QtGui/QDesktopServices>
+#include <QtXml/QXmlSimpleReader>
+#include <QtXml/QXmlInputSource>
+#include <QtXml/QXmlStreamReader>
+#include <QtXml/QXmlStreamAttributes>
+#include <QtNetwork/QNetworkRequest>
+#include <QtNetwork/QNetworkReply>
+
+using namespace TextEditor;
+using namespace Internal;
+
+Manager::Manager() : m_downloadingDefinitions(false)
+{
+ connect(&m_mimeTypeWatcher, SIGNAL(resultReadyAt(int)), this, SLOT(registerMimeType(int)));
+ connect(&m_downloadWatcher, SIGNAL(finished()), this, SLOT(downloadDefinitionsFinished()));
+}
+
+Manager::~Manager()
+{}
+
+Manager *Manager::instance()
+{
+ static Manager manager;
+ return &manager;
+}
+
+QString Manager::definitionIdByName(const QString &name) const
+{ return m_idByName.value(name); }
+
+QString Manager::definitionIdByMimeType(const QString &mimeType) const
+{ return m_idByMimeType.value(mimeType); }
+
+QString Manager::definitionIdByAnyMimeType(const QStringList &mimeTypes) const
+{
+ QString definitionId;
+ foreach (const QString &mimeType, mimeTypes) {
+ definitionId = definitionIdByMimeType(mimeType);
+ if (!definitionId.isEmpty())
+ break;
+ }
+ return definitionId;
+}
+
+QSharedPointer<HighlightDefinition> Manager::definition(const QString &id)
+{
+ if (!id.isEmpty() && !m_definitions.contains(id)) {
+ QFile definitionFile(id);
+ if (!definitionFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ return QSharedPointer<HighlightDefinition>();
+
+ QSharedPointer<HighlightDefinition> definition(new HighlightDefinition);
+ HighlightDefinitionHandler handler(definition);
+
+ QXmlInputSource source(&definitionFile);
+ QXmlSimpleReader reader;
+ reader.setContentHandler(&handler);
+ m_isBuilding.insert(id);
+ try {
+ reader.parse(source);
+ } catch (HighlighterException &) {
+ definition.clear();
+ }
+ m_isBuilding.remove(id);
+ definitionFile.close();
+
+ m_definitions.insert(id, definition);
+ }
+
+ return m_definitions.value(id);
+}
+
+QSharedPointer<HighlightDefinitionMetaData> Manager::definitionMetaData(const QString &id) const
+{ return m_definitionsMetaData.value(id); }
+
+bool Manager::isBuildingDefinition(const QString &id) const
+{ return m_isBuilding.contains(id); }
+
+void Manager::registerMimeTypes()
+{
+ clear();
+ QFuture<Core::MimeType> future =
+ QtConcurrent::run(&Manager::gatherDefinitionsMimeTypes, this);
+ m_mimeTypeWatcher.setFuture(future);
+}
+
+void Manager::gatherDefinitionsMimeTypes(QFutureInterface<Core::MimeType> &future)
+{
+ const HighlighterSettings &settings = TextEditorSettings::instance()->highlighterSettings();
+ QDir definitionsDir(settings.definitionFilesPath());
+
+ QStringList filter(QLatin1String("*.xml"));
+ definitionsDir.setNameFilters(filter);
+
+ const QFileInfoList &filesInfo = definitionsDir.entryInfoList();
+ foreach (const QFileInfo &fileInfo, filesInfo) {
+ const QSharedPointer<HighlightDefinitionMetaData> &metaData = parseMetadata(fileInfo);
+ if (metaData.isNull())
+ continue;
+
+ const QString &id = fileInfo.absoluteFilePath();
+ m_idByName.insert(metaData->name(), id);
+ m_definitionsMetaData.insert(id, metaData);
+
+ // A definition can specify multiple MIME types and file extensions/patterns. However, each
+ // thing is done with a single string. Then, there is no direct way to tell which patterns
+ // belong to which MIME types nor whether a MIME type is just an alias for the other.
+ // Currently, I associate all expressions/patterns with all MIME types from a definition.
+
+ static const QStringList textPlain(QLatin1String("text/plain"));
+
+ QList<QRegExp> patterns;
+ foreach (const QString &type, metaData->mimeTypes()) {
+ m_idByMimeType.insert(type, id);
+ Core::MimeType mimeType = Core::ICore::instance()->mimeDatabase()->findByType(type);
+ if (mimeType.isNull()) {
+ if (patterns.isEmpty()) {
+ foreach (const QString &pattern, metaData->patterns())
+ patterns.append(QRegExp(pattern, Qt::CaseSensitive, QRegExp::Wildcard));
+ }
+
+ mimeType.setType(type);
+ mimeType.setSubClassesOf(textPlain);
+ mimeType.setComment(metaData->name());
+ mimeType.setGlobPatterns(patterns);
+
+ future.reportResult(mimeType);
+ }
+ }
+ }
+}
+
+void Manager::registerMimeType(int index) const
+{
+ const Core::MimeType &mimeType = m_mimeTypeWatcher.resultAt(index);
+ TextEditorPlugin::instance()->editorFactory()->addMimeType(mimeType.type());
+ Core::ICore::instance()->mimeDatabase()->addMimeType(mimeType);
+}
+
+QSharedPointer<HighlightDefinitionMetaData> Manager::parseMetadata(const QFileInfo &fileInfo)
+{
+ static const QLatin1Char kSemiColon(';');
+ static const QLatin1Char kSlash('/');
+ static const QLatin1String kLanguage("language");
+ static const QLatin1String kArtificial("artificial");
+
+ QFile definitionFile(fileInfo.absoluteFilePath());
+ if (!definitionFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ return QSharedPointer<HighlightDefinitionMetaData>();
+
+ QSharedPointer<HighlightDefinitionMetaData> metaData(new HighlightDefinitionMetaData);
+
+ QXmlStreamReader reader(&definitionFile);
+ while (!reader.atEnd() && !reader.hasError()) {
+ if (reader.readNext() == QXmlStreamReader::StartElement &&
+ reader.name() == kLanguage) {
+ const QXmlStreamAttributes &atts = reader.attributes();
+
+ metaData->setName(atts.value(HighlightDefinitionMetaData::kName).toString());
+ metaData->setVersion(atts.value(HighlightDefinitionMetaData::kVersion).toString());
+ metaData->setPatterns(atts.value(HighlightDefinitionMetaData::kExtensions).
+ toString().split(kSemiColon, QString::SkipEmptyParts));
+
+ QStringList mimeTypes = atts.value(HighlightDefinitionMetaData::kMimeType).
+ toString().split(kSemiColon, QString::SkipEmptyParts);
+ if (mimeTypes.isEmpty()) {
+ // There are definitions which do not specify a MIME type, but specify file
+ // patterns. Creating an artificial MIME type is a workaround.
+ QString artificialType(kArtificial);
+ artificialType.append(kSlash).append(metaData->name());
+ mimeTypes.append(artificialType);
+ }
+ metaData->setMimeTypes(mimeTypes);
+
+ break;
+ }
+ }
+ reader.clear();
+ definitionFile.close();
+
+ return metaData;
+}
+
+QList<HighlightDefinitionMetaData> Manager::parseAvailableDefinitionsList(QIODevice *device) const
+{
+ static const QLatin1String kDefinition("Definition");
+
+ QList<HighlightDefinitionMetaData> metaDataList;
+ QXmlStreamReader reader(device);
+ while (!reader.atEnd() && !reader.hasError()) {
+ if (reader.readNext() == QXmlStreamReader::StartElement &&
+ reader.name() == kDefinition) {
+ const QXmlStreamAttributes &atts = reader.attributes();
+
+ HighlightDefinitionMetaData metaData;
+ metaData.setName(atts.value(HighlightDefinitionMetaData::kName).toString());
+ metaData.setUrl(QUrl(atts.value(HighlightDefinitionMetaData::kUrl).toString()));
+ metaData.setVersion(atts.value(HighlightDefinitionMetaData::kVersion).toString());
+
+ metaDataList.append(metaData);
+ }
+ }
+ reader.clear();
+
+ return metaDataList;
+}
+
+void Manager::downloadAvailableDefinitionsMetaData()
+{
+ QUrl url(QLatin1String("http://www.kate-editor.org/syntax/update-3.2.xml"));
+ QNetworkRequest request(url);
+ // Currently this takes a couple of seconds on Windows 7: QTBUG-10106.
+ QNetworkReply *reply = m_networkManager.get(request);
+ connect(reply, SIGNAL(finished()), this, SLOT(downloadAvailableDefinitionsListFinished()));
+}
+
+void Manager::downloadAvailableDefinitionsListFinished()
+{
+ if (QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender())) {
+ if (reply->error() == QNetworkReply::NoError)
+ emit definitionsMetaDataReady(parseAvailableDefinitionsList(reply));
+ else
+ emit errorDownloadingDefinitionsMetaData();
+ reply->deleteLater();
+ }
+}
+
+void Manager::downloadDefinitions(const QList<QUrl> &urls)
+{
+ const QString &savePath =
+ TextEditorSettings::instance()->highlighterSettings().definitionFilesPath() +
+ QLatin1Char('/');
+
+ m_downloaders.clear();
+ foreach (const QUrl &url, urls)
+ m_downloaders.append(new DefinitionDownloader(url, savePath));
+
+ m_downloadingDefinitions = true;
+ QFuture<void> future = QtConcurrent::map(m_downloaders, DownloaderStarter());
+ m_downloadWatcher.setFuture(future);
+ Core::ICore::instance()->progressManager()->addTask(future,
+ tr("Downloading definitions"),
+ Constants::TASK_DOWNLOAD);
+}
+
+void Manager::downloadDefinitionsFinished()
+{
+ foreach (DefinitionDownloader *downloader, m_downloaders)
+ delete downloader;
+
+ registerMimeTypes();
+ m_downloadingDefinitions = false;
+}
+
+bool Manager::isDownloadingDefinitions() const
+{
+ return m_downloadingDefinitions;
+}
+
+void Manager::showGenericHighlighterOptions() const
+{
+ Core::ICore::instance()->showOptionsDialog(Constants::TEXT_EDITOR_SETTINGS_CATEGORY,
+ Constants::TEXT_EDITOR_HIGHLIGHTER_SETTINGS);
+}
+
+void Manager::clear()
+{
+ m_idByName.clear();
+ m_idByMimeType.clear();
+ m_definitions.clear();
+ m_definitionsMetaData.clear();
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef MANAGER_H
+#define MANAGER_H
+
+#include "highlightdefinitionmetadata.h"
+
+#include <coreplugin/mimedatabase.h>
+
+#include <QtCore/QString>
+#include <QtCore/QHash>
+#include <QtCore/QSet>
+#include <QtCore/QUrl>
+#include <QtCore/QList>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QFutureWatcher>
+#include <QtNetwork/QNetworkAccessManager>
+
+QT_BEGIN_NAMESPACE
+class QFileInfo;
+class QStringList;
+class QIODevice;
+template <class> class QFutureInterface;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+namespace Internal {
+
+class HighlightDefinition;
+class DefinitionDownloader;
+
+class Manager : public QObject
+{
+ Q_OBJECT
+public:
+ virtual ~Manager();
+ static Manager *instance();
+
+ QString definitionIdByName(const QString &name) const;
+ QString definitionIdByMimeType(const QString &mimeType) const;
+ QString definitionIdByAnyMimeType(const QStringList &mimeTypes) const;
+
+ bool isBuildingDefinition(const QString &id) const;
+
+ QSharedPointer<HighlightDefinition> definition(const QString &id);
+ QSharedPointer<HighlightDefinitionMetaData> definitionMetaData(const QString &id) const;
+
+ void downloadAvailableDefinitionsMetaData();
+ void downloadDefinitions(const QList<QUrl> &urls);
+ bool isDownloadingDefinitions() const;
+
+public slots:
+ void registerMimeTypes();
+ void showGenericHighlighterOptions() const;
+
+private slots:
+ void registerMimeType(int index) const;
+ void downloadAvailableDefinitionsListFinished();
+ void downloadDefinitionsFinished();
+
+private:
+ Manager();
+ Q_DISABLE_COPY(Manager)
+
+ void gatherDefinitionsMimeTypes(QFutureInterface<Core::MimeType> &future);
+ QSharedPointer<HighlightDefinitionMetaData> parseMetadata(const QFileInfo &fileInfo);
+ QList<HighlightDefinitionMetaData> parseAvailableDefinitionsList(QIODevice *device) const;
+ void clear();
+
+ QHash<QString, QString> m_idByName;
+ QHash<QString, QString> m_idByMimeType;
+ QHash<QString, QSharedPointer<HighlightDefinition> > m_definitions;
+ QHash<QString, QSharedPointer<HighlightDefinitionMetaData> > m_definitionsMetaData;
+ QSet<QString> m_isBuilding;
+
+ QList<DefinitionDownloader *> m_downloaders;
+ bool m_downloadingDefinitions;
+ QNetworkAccessManager m_networkManager;
+
+ QFutureWatcher<void> m_downloadWatcher;
+ QFutureWatcher<Core::MimeType> m_mimeTypeWatcher;
+
+signals:
+ void definitionsMetaDataReady(const QList<Internal::HighlightDefinitionMetaData>&);
+ void errorDownloadingDefinitionsMetaData();
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // MANAGER_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "progressdata.h"
+
+#include <QtCore/QtGlobal>
+
+using namespace TextEditor;
+using namespace Internal;
+
+ProgressData::ProgressData() :
+ m_offset(0),
+ m_savedOffset(-1),
+ m_onlySpacesSoFar(true),
+ m_willContinueLine(false)
+{}
+
+void ProgressData::setOffset(const int offset)
+{ m_offset = offset; }
+
+int ProgressData::offset() const
+{ return m_offset; }
+
+void ProgressData::incrementOffset()
+{ ++m_offset; }
+
+void ProgressData::incrementOffset(const int increment)
+{ m_offset += increment; }
+
+void ProgressData::saveOffset()
+{ m_savedOffset = m_offset; }
+
+void ProgressData::restoreOffset()
+{
+ Q_ASSERT(m_savedOffset != -1);
+ m_offset = m_savedOffset;
+ m_savedOffset = -1;
+}
+
+void ProgressData::setOnlySpacesSoFar(const bool onlySpaces)
+{ m_onlySpacesSoFar = onlySpaces; }
+
+bool ProgressData::onlySpacesSoFar() const
+{ return m_onlySpacesSoFar; }
+
+void ProgressData::setWillContinueLine(const bool willContinue)
+{ m_willContinueLine = willContinue; }
+
+bool ProgressData::willContinueLine() const
+{ return m_willContinueLine; }
+
+void ProgressData::setCaptures(const QStringList &captures)
+{ m_captures = captures; }
+
+const QStringList &ProgressData::captures() const
+{ return m_captures; }
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef PROGRESSDATA_H
+#define PROGRESSDATA_H
+
+#include <QtCore/QStringList>
+
+namespace TextEditor {
+namespace Internal {
+
+class ProgressData
+{
+public:
+ ProgressData();
+
+ void setOffset(const int offset);
+ int offset() const;
+
+ void incrementOffset();
+ void incrementOffset(const int increment);
+
+ void saveOffset();
+ void restoreOffset();
+
+ void setOnlySpacesSoFar(const bool onlySpaces);
+ bool onlySpacesSoFar() const;
+
+ void setWillContinueLine(const bool willContinue);
+ bool willContinueLine() const;
+
+ void setCaptures(const QStringList &captures);
+ const QStringList &captures() const;
+
+private:
+ int m_offset;
+ int m_savedOffset;
+ bool m_onlySpacesSoFar;
+ bool m_willContinueLine;
+ QStringList m_captures;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // PROGRESSDATA_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef REUSE_H
+#define REUSE_H
+
+#include <Qt>
+#include <QtCore/QString>
+#include <QtCore/QLatin1String>
+#include <QtCore/QChar>
+#include <QtGui/QFont>
+
+namespace TextEditor {
+namespace Internal {
+
+inline bool toBool(const QString &s)
+{
+ static const QLatin1String kTrue("true");
+ static const QLatin1String k1("1");
+
+ if (s.toLower() == kTrue || s == k1)
+ return true;
+ return false;
+}
+
+
+inline Qt::CaseSensitivity toCaseSensitivity(const bool sensitive)
+{
+ if (sensitive)
+ return Qt::CaseSensitive;
+ return Qt::CaseInsensitive;
+}
+
+inline QFont::Weight toFontWeight(const bool bold)
+{
+ if (bold)
+ return QFont::Bold;
+ else
+ return QFont::Normal;
+}
+
+inline bool isOctalDigit(const QChar &c)
+{
+ static const QLatin1Char k0('0');
+ static const QLatin1Char k7('7');
+
+ return c >= k0 && c <= k7;
+}
+
+inline bool isHexDigit(const QChar &c)
+{
+ static const QLatin1Char k0('0');
+ static const QLatin1Char k9('9');
+ static const QLatin1Char kA('A');
+ static const QLatin1Char kF('F');
+ static const QLatin1Char ka('a');
+ static const QLatin1Char kf('f');
+
+ if ((c >= k0 && c <= k9) || (c >= kA && c <= kF) || (c >= ka && c <= kf))
+ return true;
+
+ return false;
+}
+
+inline void setStartCharacter(QChar *c, const QString &character)
+{
+ if (!character.isEmpty())
+ *c = character.at(0);
+}
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // REUSE_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "rule.h"
+#include "highlighterexception.h"
+#include "progressdata.h"
+#include "highlightdefinition.h"
+#include "reuse.h"
+
+#include <QtCore/QStringList>
+
+#include <functional>
+
+using namespace TextEditor;
+using namespace Internal;
+
+const QLatin1Char Rule::kBackSlash('\\');
+const QLatin1Char Rule::kUnderscore('_');
+const QLatin1Char Rule::kDot('.');
+const QLatin1Char Rule::kPlus('+');
+const QLatin1Char Rule::kMinus('-');
+const QLatin1Char Rule::kZero('0');
+const QLatin1Char Rule::kQuote('\"');
+const QLatin1Char Rule::kSingleQuote('\'');
+const QLatin1Char Rule::kQuestion('?');
+const QLatin1Char Rule::kX('x');
+const QLatin1Char Rule::kA('a');
+const QLatin1Char Rule::kB('b');
+const QLatin1Char Rule::kE('e');
+const QLatin1Char Rule::kF('f');
+const QLatin1Char Rule::kN('n');
+const QLatin1Char Rule::kR('r');
+const QLatin1Char Rule::kT('t');
+const QLatin1Char Rule::kV('v');
+
+Rule::Rule(bool consumesNonSpace) :
+ m_lookAhead(false), m_firstNonSpace(false), m_column(-1), m_consumesNonSpace(consumesNonSpace)
+{}
+
+Rule::~Rule()
+{}
+
+void Rule::setContext(const QString &context)
+{ m_context = context; }
+
+const QString &Rule::context() const
+{ return m_context; }
+
+void Rule::setItemData(const QString &itemData)
+{ m_itemData = itemData; }
+
+const QString &Rule::itemData() const
+{ return m_itemData; }
+
+void Rule::setBeginRegion(const QString &begin)
+{ m_beginRegion = begin; }
+
+const QString &Rule::beginRegion() const
+{ return m_beginRegion; }
+
+void Rule::setEndRegion(const QString &end)
+{ m_endRegion = end; }
+
+const QString &Rule::endRegion() const
+{ return m_endRegion; }
+
+void Rule::setLookAhead(const QString &lookAhead)
+{ m_lookAhead = toBool(lookAhead); }
+
+bool Rule::isLookAhead() const
+{ return m_lookAhead; }
+
+void Rule::setFirstNonSpace(const QString &firstNonSpace)
+{ m_firstNonSpace = toBool(firstNonSpace); }
+
+bool Rule::isFirstNonSpace() const
+{ return m_firstNonSpace; }
+
+void Rule::setColumn(const QString &column)
+{
+ bool ok;
+ m_column = column.toInt(&ok);
+ if (!ok)
+ m_column = -1;
+}
+
+int Rule::column() const
+{ return m_column; }
+
+void Rule::addChild(const QSharedPointer<Rule> &rule)
+{ m_childRules.append(rule); }
+
+bool Rule::hasChild() const
+{ return !m_childRules.isEmpty(); }
+
+const QList<QSharedPointer<Rule> > &Rule::childs() const
+{ return m_childRules; }
+
+void Rule::setDefinition(const QSharedPointer<HighlightDefinition> &definition)
+{ m_definition = definition; }
+
+const QSharedPointer<HighlightDefinition> &Rule::definition() const
+{ return m_definition; }
+
+template <class predicate_t>
+bool Rule::predicateMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress,
+ const predicate_t &p) const
+{
+ int original = progress->offset();
+ while (progress->offset() < length && p(text.at(progress->offset())))
+ progress->incrementOffset();
+
+ if (original != progress->offset())
+ return true;
+
+ return false;
+}
+
+bool Rule::charPredicateMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool (QChar::* predicate)() const) const
+{
+ return predicateMatchSucceed(text, length, progress, std::mem_fun_ref(predicate));
+}
+
+bool Rule::charPredicateMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool (*predicate)(const QChar &)) const
+{
+ return predicateMatchSucceed(text, length, progress, std::ptr_fun(predicate));
+}
+
+bool Rule::matchSucceed(const QString &text, const int length, ProgressData *progress) const
+{
+ if (m_firstNonSpace && !progress->onlySpacesSoFar())
+ return false;
+
+ if (m_column != -1 && m_column != progress->offset())
+ return false;
+
+ int original = progress->offset();
+ if (doMatchSucceed(text, length, progress)) {
+ if (progress->onlySpacesSoFar() && !m_lookAhead && m_consumesNonSpace)
+ progress->setOnlySpacesSoFar(false);
+
+ if (m_lookAhead)
+ progress->setOffset(original);
+
+ return true;
+ }
+
+ return false;
+}
+
+Rule *Rule::clone() const
+{ return doClone(); }
+
+bool Rule::matchCharacter(const QString &text,
+ const int length,
+ ProgressData *progress,
+ const QChar &c,
+ bool saveRestoreOffset) const
+{
+ Q_UNUSED(length)
+ Q_ASSERT(progress->offset() < length);
+
+ if (text.at(progress->offset()) == c) {
+ if (saveRestoreOffset)
+ progress->saveOffset();
+ progress->incrementOffset();
+ return true;
+ }
+
+ return false;
+}
+
+bool Rule::matchEscapeSequence(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool saveRestoreOffset) const
+{
+ if (matchCharacter(text, length, progress, kBackSlash, saveRestoreOffset)) {
+
+ if (progress->offset() < length) {
+ const QChar &c = text.at(progress->offset());
+ if (c == kA || c == kB || c == kE || c == kF || c == kN || c == kR || c == kT ||
+ c == kV || c == kQuestion || c == kSingleQuote || c == kQuote || c == kBackSlash) {
+ progress->incrementOffset();
+ return true;
+ } else if (saveRestoreOffset) {
+ progress->restoreOffset();
+ }
+ } else if (saveRestoreOffset) {
+ progress->restoreOffset();
+ }
+ }
+
+ return false;
+}
+
+bool Rule::matchOctalSequence(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool saveRestoreOffset) const
+{
+ // An octal sequence is identified as in the C++ Standard.
+ // octal-escape-sequence:
+ // \ octal-digit
+ // \ octal-digit octal-digit
+ // \ octal-digit octal-digit octal-digit
+
+ if (matchCharacter(text, length, progress, kBackSlash, saveRestoreOffset)) {
+
+ int count = 0;
+ while (progress->offset() < length &&
+ count < 3 &&
+ isOctalDigit(text.at(progress->offset()))) {
+ ++count;
+ progress->incrementOffset();
+ }
+
+ if (count > 0)
+ return true;
+ else if (saveRestoreOffset)
+ progress->restoreOffset();
+ }
+
+ return false;
+}
+
+bool Rule::matchHexSequence(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool saveRestoreOffset) const
+{
+ // An hex sequence is identified as in the C++ Standard.
+ // hexadecimal-escape-sequence:
+ // \x hexadecimal-digit
+ // hexadecimal-escape-sequence hexadecimal-digit
+
+ if (matchCharacter(text, length, progress, kBackSlash, saveRestoreOffset)) {
+
+ if (progress->offset() < length && matchCharacter(text, length, progress, kX, false)) {
+ bool found = false;
+ while (progress->offset() < length && isHexDigit(text.at(progress->offset()))) {
+ if (!found)
+ found = true;
+ progress->incrementOffset();
+ }
+
+ if (found)
+ return true;
+ else if (saveRestoreOffset)
+ progress->restoreOffset();
+ } else if (saveRestoreOffset) {
+ progress->restoreOffset();
+ }
+ }
+
+ return false;
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef RULE_H
+#define RULE_H
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QSharedPointer>
+
+namespace TextEditor {
+namespace Internal {
+
+class ProgressData;
+class HighlightDefinition;
+
+class Rule
+{
+public:
+ Rule(bool consumesNonSpace = true);
+ virtual ~Rule();
+
+ void setContext(const QString &context);
+ const QString &context() const;
+
+ void setItemData(const QString &itemData);
+ const QString &itemData() const;
+
+ void setBeginRegion(const QString &begin);
+ const QString &beginRegion() const;
+
+ void setEndRegion(const QString &end);
+ const QString &endRegion() const;
+
+ void setLookAhead(const QString &lookAhead);
+ bool isLookAhead() const;
+
+ void setFirstNonSpace(const QString &firstNonSpace);
+ bool isFirstNonSpace() const;
+
+ void setColumn(const QString &column);
+ int column() const;
+
+ void addChild(const QSharedPointer<Rule> &rule);
+ const QList<QSharedPointer<Rule> > &childs() const;
+ bool hasChild() const;
+
+ void setDefinition(const QSharedPointer<HighlightDefinition> &definition);
+ const QSharedPointer<HighlightDefinition> &definition() const;
+
+ bool matchSucceed(const QString &text, const int length, ProgressData *progress) const;
+
+ Rule *clone() const;
+
+protected:
+ bool charPredicateMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool (QChar::* predicate)() const) const;
+ bool charPredicateMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool (*predicate)(const QChar &)) const;
+
+ bool matchCharacter(const QString &text,
+ const int length,
+ ProgressData *progress,
+ const QChar &c,
+ bool saveRestoreOffset = true) const;
+ bool matchEscapeSequence(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool saveRestoreOffset = true) const;
+ bool matchOctalSequence(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool saveRestoreOffset = true) const;
+ bool matchHexSequence(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool saveRestoreOffset = true) const;
+
+ static const QLatin1Char kBackSlash;
+ static const QLatin1Char kUnderscore;
+ static const QLatin1Char kDot;
+ static const QLatin1Char kPlus;
+ static const QLatin1Char kMinus;
+ static const QLatin1Char kZero;
+ static const QLatin1Char kQuote;
+ static const QLatin1Char kSingleQuote;
+ static const QLatin1Char kQuestion;
+ static const QLatin1Char kX;
+ static const QLatin1Char kA;
+ static const QLatin1Char kB;
+ static const QLatin1Char kE;
+ static const QLatin1Char kF;
+ static const QLatin1Char kN;
+ static const QLatin1Char kR;
+ static const QLatin1Char kT;
+ static const QLatin1Char kV;
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const = 0;
+
+ virtual Rule *doClone() const = 0;
+
+ template <class predicate_t>
+ bool predicateMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress,
+ const predicate_t &p) const;
+
+ QString m_context;
+ QString m_itemData;
+ QString m_beginRegion;
+ QString m_endRegion;
+ bool m_lookAhead;
+ bool m_firstNonSpace;
+ int m_column;
+ bool m_consumesNonSpace;
+
+ QList<QSharedPointer<Rule> > m_childRules;
+
+ // Rules are represented within contexts. However, they have their own definition because
+ // of externally included rules.
+ QSharedPointer<HighlightDefinition> m_definition;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // RULE_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "specificrules.h"
+#include "highlightdefinition.h"
+#include "keywordlist.h"
+#include "progressdata.h"
+#include "reuse.h"
+
+#include <QLatin1Char>
+
+using namespace TextEditor;
+using namespace Internal;
+
+namespace {
+
+void replaceByCaptures(QChar *c, const QStringList &captures)
+{
+ int index = c->digitValue();
+ if (index > 0) {
+ const QString &capture = captures.at(index);
+ if (!capture.isEmpty())
+ *c = capture.at(0);
+ }
+}
+
+void replaceByCaptures(QString *s, const QStringList &captures)
+{
+ static const QLatin1Char kPercent('%');
+
+ int index;
+ int from = 0;
+ while ((index = s->indexOf(kPercent, from)) != -1) {
+ from = index + 1;
+
+ QString accumulator;
+ while (from < s->length() && s->at(from).isDigit()) {
+ accumulator.append(s->at(from));
+ ++from;
+ }
+
+ bool ok;
+ int number = accumulator.toInt(&ok);
+ Q_ASSERT(ok);
+
+ s->replace(index, accumulator.length() + 1, captures.at(number));
+ index = from;
+ }
+}
+}
+
+// DetectChar
+void DetectCharRule::setChar(const QString &character)
+{ setStartCharacter(&m_char, character); }
+
+void DetectCharRule::doReplaceExpressions(const QStringList &captures)
+{ replaceByCaptures(&m_char, captures); }
+
+bool DetectCharRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ return matchCharacter(text, length, progress, m_char);
+}
+
+// Detect2Chars
+void Detect2CharsRule::setChar(const QString &character)
+{ setStartCharacter(&m_char, character); }
+
+void Detect2CharsRule::setChar1(const QString &character)
+{ setStartCharacter(&m_char1, character); }
+
+void Detect2CharsRule::doReplaceExpressions(const QStringList &captures)
+{
+ replaceByCaptures(&m_char, captures);
+ replaceByCaptures(&m_char1, captures);
+}
+
+bool Detect2CharsRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (matchCharacter(text, length, progress, m_char)) {
+ if (progress->offset() < length && matchCharacter(text, length, progress, m_char1, false))
+ return true;
+ else
+ progress->restoreOffset();
+ }
+
+ return false;
+}
+
+// AnyChar
+void AnyCharRule::setCharacterSet(const QString &s)
+{ m_characterSet = s; }
+
+bool AnyCharRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ Q_UNUSED(length)
+
+ if (m_characterSet.contains(text.at(progress->offset()))) {
+ progress->incrementOffset();
+ return true;
+ }
+
+ return false;
+}
+
+// StringDetect
+void StringDetectRule::setString(const QString &s)
+{
+ m_string = s;
+ m_length = m_string.length();
+}
+
+void StringDetectRule::setInsensitive(const QString &insensitive)
+{ m_caseSensitivity = toCaseSensitivity(!toBool(insensitive)); }
+
+void StringDetectRule::doReplaceExpressions(const QStringList &captures)
+{
+ replaceByCaptures(&m_string, captures);
+ m_length = m_string.length();
+}
+
+bool StringDetectRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (length - progress->offset() >= m_length) {
+ QString candidate = text.fromRawData(text.unicode() + progress->offset(), m_length);
+ if (candidate.compare(m_string, m_caseSensitivity) == 0) {
+ progress->incrementOffset(m_length);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// RegExpr
+void RegExprRule::setPattern(const QString &pattern)
+{ m_expression.setPattern(pattern); }
+
+void RegExprRule::setInsensitive(const QString &insensitive)
+{ m_expression.setCaseSensitivity(toCaseSensitivity(!toBool(insensitive))); }
+
+void RegExprRule::setMinimal(const QString &minimal)
+{ m_expression.setMinimal(toBool(minimal)); }
+
+void RegExprRule::doReplaceExpressions(const QStringList &captures)
+{
+ QString s = m_expression.pattern();
+ replaceByCaptures(&s, captures);
+ m_expression.setPattern(s);
+}
+
+bool RegExprRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ Q_UNUSED(length)
+
+ // This is not documented but a regular expression match is considered valid if it starts
+ // at the current position and if the match length is not zero.
+ const int offset = progress->offset();
+ if (m_expression.indexIn(text, offset, QRegExp::CaretAtZero) == offset) {
+ if (m_expression.matchedLength() == 0)
+ return false;
+ progress->incrementOffset(m_expression.matchedLength());
+ progress->setCaptures(m_expression.capturedTexts());
+ return true;
+ }
+
+ return false;
+}
+
+// Keyword
+KeywordRule::KeywordRule(const QSharedPointer<HighlightDefinition> &definition) :
+ m_overrideGlobal(false)
+{
+ setDefinition(definition);
+}
+
+KeywordRule::~KeywordRule()
+{}
+
+void KeywordRule::setInsensitive(const QString &insensitive)
+{
+ if (!insensitive.isEmpty()) {
+ m_overrideGlobal = true;
+ m_localCaseSensitivity = toCaseSensitivity(!toBool(insensitive));
+ }
+}
+
+void KeywordRule::setList(const QString &listName)
+{ m_list = definition()->keywordList(listName); }
+
+bool KeywordRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ int current = progress->offset();
+
+ if (current > 0 && !definition()->isDelimiter(text.at(current - 1)))
+ return false;
+ if (definition()->isDelimiter(text.at(current)))
+ return false;
+
+ while (current < length && !definition()->isDelimiter(text.at(current)))
+ ++current;
+
+ QString candidate =
+ QString::fromRawData(text.unicode() + progress->offset(), current - progress->offset());
+ if ((m_overrideGlobal && m_list->isKeyword(candidate, m_localCaseSensitivity)) ||
+ (!m_overrideGlobal && m_list->isKeyword(candidate, definition()->keywordsSensitive()))) {
+ progress->setOffset(current);
+ return true;
+ }
+
+ return false;
+}
+
+// Int
+bool IntRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ const int offset = progress->offset();
+
+ // This is necessary to correctly highlight an invalid octal like 09, for example.
+ if (offset > 0 && text.at(offset - 1).isDigit())
+ return false;
+
+ if (text.at(offset).isDigit() && text.at(offset) != kZero) {
+ progress->incrementOffset();
+ charPredicateMatchSucceed(text, length, progress, &QChar::isDigit);
+ return true;
+ }
+
+ return false;
+}
+
+// Float
+bool FloatRule::doMatchSucceed(const QString &text, const int length, ProgressData *progress) const
+{
+ progress->saveOffset();
+
+ bool integralPart = charPredicateMatchSucceed(text, length, progress, &QChar::isDigit);
+
+ bool decimalPoint = false;
+ if (progress->offset() < length && text.at(progress->offset()) == kDot) {
+ progress->incrementOffset();
+ decimalPoint = true;
+ }
+
+ bool fractionalPart = charPredicateMatchSucceed(text, length, progress, &QChar::isDigit);
+
+ bool exponentialPart = false;
+ int offset = progress->offset();
+ if (offset < length && (text.at(offset) == kE || text.at(offset).toLower() == kE)) {
+ progress->incrementOffset();
+
+ offset = progress->offset();
+ if (offset < length && (text.at(offset) == kPlus || text.at(offset) == kMinus))
+ progress->incrementOffset();
+
+ if (charPredicateMatchSucceed(text, length, progress, &QChar::isDigit)) {
+ exponentialPart = true;
+ } else {
+ progress->restoreOffset();
+ return false;
+ }
+ }
+
+ if ((integralPart || fractionalPart) && (decimalPoint || exponentialPart))
+ return true;
+
+ progress->restoreOffset();
+ return false;
+}
+
+// COctal
+bool HlCOctRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (matchCharacter(text, length, progress, kZero)) {
+ // In the definition files the number matching rules which are more restrictive should
+ // appear before the rules which are least resctritive. Although this happens in general
+ // there is at least one case where this is not strictly followed for existent definition
+ // files (specifically, HlCHex comes before HlCOct). So the condition below.
+ const int offset = progress->offset();
+ if (offset < length && (text.at(offset) == kX || text.at(offset).toLower() == kX)) {
+ progress->restoreOffset();
+ return false;
+ }
+
+ charPredicateMatchSucceed(text, length, progress, &isOctalDigit);
+ return true;
+ }
+
+ return false;
+}
+
+// CHex
+bool HlCHexRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (matchCharacter(text, length, progress, kZero)) {
+ const int offset = progress->offset();
+ if (offset < length && text.at(offset) != kX && text.at(offset).toLower() != kX) {
+ progress->restoreOffset();
+ return false;
+ }
+
+ progress->incrementOffset();
+ if (charPredicateMatchSucceed(text, length, progress, &isHexDigit))
+ return true;
+ else
+ progress->restoreOffset();
+ }
+
+ return false;
+}
+
+// CString
+bool HlCStringCharRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (matchEscapeSequence(text, length, progress))
+ return true;
+
+ if (matchOctalSequence(text, length, progress))
+ return true;
+
+ if (matchHexSequence(text, length, progress))
+ return true;
+
+ return false;
+}
+
+// CChar
+bool HlCCharRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (matchCharacter(text, length, progress, kSingleQuote)) {
+ if (progress->offset() < length) {
+ if (text.at(progress->offset()) != kBackSlash &&
+ text.at(progress->offset()) != kSingleQuote) {
+ progress->incrementOffset();
+ } else if (!matchEscapeSequence(text, length, progress, false)) {
+ progress->restoreOffset();
+ return false;
+ }
+
+ if (progress->offset() < length &&
+ matchCharacter(text, length, progress, kSingleQuote, false)) {
+ return true;
+ } else {
+ progress->restoreOffset();
+ }
+ } else {
+ progress->restoreOffset();
+ }
+ }
+
+ return false;
+}
+
+// RangeDetect
+void RangeDetectRule::setChar(const QString &character)
+{ setStartCharacter(&m_char, character); }
+
+void RangeDetectRule::setChar1(const QString &character)
+{ setStartCharacter(&m_char1, character); }
+
+bool RangeDetectRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (matchCharacter(text, length, progress, m_char)) {
+ while (progress->offset() < length) {
+ if (matchCharacter(text, length, progress, m_char1, false))
+ return true;
+ progress->incrementOffset();
+ }
+ progress->restoreOffset();
+ }
+
+ return false;
+}
+
+// LineContinue
+bool LineContinueRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (progress->offset() != length - 1)
+ return false;
+
+ if (text.at(progress->offset()) == kBackSlash) {
+ progress->incrementOffset();
+ progress->setWillContinueLine(true);
+ return true;
+ }
+
+ return false;
+}
+
+// DetectSpaces
+DetectSpacesRule::DetectSpacesRule() : Rule(false)
+{}
+
+bool DetectSpacesRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ return charPredicateMatchSucceed(text, length, progress, &QChar::isSpace);
+}
+
+// DetectIdentifier
+bool DetectIdentifierRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ // Identifiers are characterized by a letter or underscore as the first character and then
+ // zero or more word characters (\w*).
+ if (text.at(progress->offset()).isLetter() || text.at(progress->offset()) == kUnderscore) {
+ progress->incrementOffset();
+ while (progress->offset() < length) {
+ const QChar ¤t = text.at(progress->offset());
+ if (current.isLetterOrNumber() || current.isMark() || current == kUnderscore)
+ progress->incrementOffset();
+ else
+ break;
+ }
+ return true;
+ }
+ return false;
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef SPECIFICRULES_H
+#define SPECIFICRULES_H
+
+#include "rule.h"
+#include "dynamicrule.h"
+
+#include <QtCore/QChar>
+#include <QtCore/QString>
+#include <QtCore/QRegExp>
+#include <QtCore/QSharedPointer>
+
+namespace TextEditor {
+namespace Internal {
+
+class KeywordList;
+class HighlightDefinition;
+
+class DetectCharRule : public DynamicRule
+{
+public:
+ virtual ~DetectCharRule() {}
+
+ void setChar(const QString &character);
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual DetectCharRule *doClone() const { return new DetectCharRule(*this); }
+ virtual void doReplaceExpressions(const QStringList &captures);
+
+ QChar m_char;
+};
+
+class Detect2CharsRule : public DynamicRule
+{
+public:
+ virtual ~Detect2CharsRule() {}
+
+ void setChar(const QString &character);
+ void setChar1(const QString &character);
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual Detect2CharsRule *doClone() const { return new Detect2CharsRule(*this); }
+ virtual void doReplaceExpressions(const QStringList &captures);
+
+ QChar m_char;
+ QChar m_char1;
+};
+
+class AnyCharRule : public Rule
+{
+public:
+ virtual ~AnyCharRule() {}
+
+ void setCharacterSet(const QString &s);
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual AnyCharRule *doClone() const { return new AnyCharRule(*this); }
+
+ QString m_characterSet;
+};
+
+class StringDetectRule : public DynamicRule
+{
+public:
+ virtual ~StringDetectRule() {}
+
+ void setString(const QString &s);
+ void setInsensitive(const QString &insensitive);
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual StringDetectRule *doClone() const { return new StringDetectRule(*this); }
+ virtual void doReplaceExpressions(const QStringList &captures);
+
+ QString m_string;
+ int m_length;
+ Qt::CaseSensitivity m_caseSensitivity;
+};
+
+class RegExprRule : public DynamicRule
+{
+public:
+ virtual ~RegExprRule() {}
+
+ void setPattern(const QString &pattern);
+ void setInsensitive(const QString &insensitive);
+ void setMinimal(const QString &minimal);
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual RegExprRule *doClone() const { return new RegExprRule(*this); }
+ virtual void doReplaceExpressions(const QStringList &captures);
+
+ QRegExp m_expression;
+};
+
+class KeywordRule : public Rule
+{
+public:
+ KeywordRule(const QSharedPointer<HighlightDefinition> &definition);
+ virtual ~KeywordRule();
+
+ void setInsensitive(const QString &insensitive);
+ void setList(const QString &listName);
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual KeywordRule *doClone() const { return new KeywordRule(*this); }
+
+ bool m_overrideGlobal;
+ Qt::CaseSensitivity m_localCaseSensitivity;
+ QSharedPointer<KeywordList> m_list;
+};
+
+class IntRule : public Rule
+{
+public:
+ virtual ~IntRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual IntRule *doClone() const { return new IntRule(*this); }
+};
+
+class FloatRule : public Rule
+{
+public:
+ virtual ~FloatRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual FloatRule *doClone() const { return new FloatRule(*this); }
+};
+
+class HlCOctRule : public Rule
+{
+public:
+ virtual ~HlCOctRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual HlCOctRule *doClone() const { return new HlCOctRule(*this); }
+};
+
+class HlCHexRule : public Rule
+{
+public:
+ virtual ~HlCHexRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual HlCHexRule *doClone() const { return new HlCHexRule(*this); }
+};
+
+class HlCStringCharRule : public Rule
+{
+public:
+ virtual ~HlCStringCharRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual HlCStringCharRule *doClone() const { return new HlCStringCharRule(*this); }
+};
+
+class HlCCharRule : public Rule
+{
+public:
+ virtual ~HlCCharRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual HlCCharRule *doClone() const { return new HlCCharRule(*this); }
+};
+
+class RangeDetectRule : public Rule
+{
+public:
+ virtual ~RangeDetectRule() {}
+
+ void setChar(const QString &character);
+ void setChar1(const QString &character);
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual RangeDetectRule *doClone() const { return new RangeDetectRule(*this); }
+
+ QChar m_char;
+ QChar m_char1;
+};
+
+class LineContinueRule : public Rule
+{
+public:
+ virtual ~LineContinueRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual LineContinueRule *doClone() const { return new LineContinueRule(*this); }
+};
+
+class DetectSpacesRule : public Rule
+{
+public:
+ DetectSpacesRule();
+ virtual ~DetectSpacesRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual DetectSpacesRule *doClone() const { return new DetectSpacesRule(*this); }
+};
+
+class DetectIdentifierRule : public Rule
+{
+public:
+ virtual ~DetectIdentifierRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual DetectIdentifierRule *doClone() const { return new DetectIdentifierRule(*this); }
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // SPECIFICRULES_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "indenter.h"
+#include "tabsettings.h"
+
+using namespace TextEditor;
+
+Indenter::Indenter()
+{}
+
+Indenter::~Indenter()
+{}
+
+void Indenter::indentBlock(QTextDocument *doc,
+ QTextBlock block,
+ QChar typedChar,
+ const TabSettings &ts)
+{
+ doIndentBlock(doc, block, typedChar, ts);
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef INDENTER_H
+#define INDENTER_H
+
+#include "texteditor_global.h"
+
+#include <QtCore/QChar>
+#include <QtGui/QTextBlock>
+
+QT_BEGIN_NAMESPACE
+class QTextDocument;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+struct TabSettings;
+
+class TEXTEDITOR_EXPORT Indenter
+{
+public:
+ Indenter();
+ virtual ~Indenter();
+
+ void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar, const TabSettings &ts);
+
+private:
+ virtual void doIndentBlock(QTextDocument *doc,
+ QTextBlock block,
+ QChar typedChar,
+ const TabSettings &ts) = 0;
+};
+
+} // namespace TextEditor
+
+#endif // INDENTER_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "normalindenter.h"
+#include "tabsettings.h"
+
+#include <QtGui/QTextDocument>
+
+using namespace TextEditor;
+
+NormalIndenter::NormalIndenter()
+{}
+
+NormalIndenter::~NormalIndenter()
+{}
+
+// Indent a text block based on previous line.
+// Simple text paragraph layout:
+// aaaa aaaa
+//
+// bbb bb
+// bbb bb
+//
+// - list
+// list line2
+//
+// - listn
+//
+// ccc
+//
+// @todo{Add formatting to wrap paragraphs. This requires some
+// hoops as the current indentation routines are not prepared
+// for additional block being inserted. It might be possible
+// to do in 2 steps (indenting/wrapping)}
+//
+void NormalIndenter::doIndentBlock(QTextDocument *doc,
+ QTextBlock block,
+ QChar typedChar,
+ const TextEditor::TabSettings &ts)
+{
+ Q_UNUSED(typedChar)
+
+ // At beginning: Leave as is.
+ if (block == doc->begin())
+ return;
+
+ const QTextBlock previous = block.previous();
+ const QString previousText = previous.text();
+ // Empty line indicates a start of a new paragraph. Leave as is.
+ if (previousText.isEmpty() || previousText.trimmed().isEmpty())
+ return;
+
+ // Just use previous line.
+ // Skip blank characters when determining the indentation
+ int i = 0;
+ while (i < previousText.size()) {
+ if (!previousText.at(i).isSpace()) {
+ ts.indentLine(block, ts.columnAt(previousText, i));
+ break;
+ }
+ ++i;
+ }
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef NORMALINDENTER_H
+#define NORMALINDENTER_H
+
+#include "indenter.h"
+
+namespace TextEditor {
+
+class TEXTEDITOR_EXPORT NormalIndenter : public Indenter
+{
+public:
+ NormalIndenter();
+ virtual ~NormalIndenter();
+
+private:
+ virtual void doIndentBlock(QTextDocument *doc,
+ QTextBlock block,
+ QChar typedChar,
+ const TabSettings &ts);
+};
+
+} // namespace TextEditor
+
+#endif // NORMALINDENTER_H
#include "tabsettings.h"
#include "texteditorconstants.h"
#include "texteditorplugin.h"
+#include "texteditorsettings.h"
+#include "basetextdocument.h"
+#include "highlightdefinition.h"
+#include "highlighter.h"
+#include "highlighterexception.h"
+#include "highlightersettings.h"
+#include "manager.h"
+#include "context.h"
+#include "normalindenter.h"
+#include "fontsettings.h"
#include <coreplugin/coreconstants.h>
#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/mimedatabase.h>
+
+#include <QtCore/QSharedPointer>
+#include <QtCore/QFileInfo>
+
+#include <QDebug>
using namespace TextEditor;
using namespace TextEditor::Internal;
}
PlainTextEditor::PlainTextEditor(QWidget *parent)
- : BaseTextEditor(parent)
+ : BaseTextEditor(parent),
+ m_isMissingSyntaxDefinition(true)
{
setRevisionsVisible(true);
setMarksVisible(true);
setMimeType(QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT));
setDisplayName(tr(Core::Constants::K_DEFAULT_TEXT_EDITOR_DISPLAY_NAME));
+
+ m_commentDefinition.clearCommentStyles();
+
+ connect(file(), SIGNAL(changed()), this, SLOT(fileChanged()));
}
+PlainTextEditor::~PlainTextEditor()
+{}
+
QList<int> PlainTextEditorEditable::context() const
{
return m_context;
return QLatin1String(Core::Constants::K_DEFAULT_TEXT_EDITOR_ID);
}
-// Indent a text block based on previous line.
-// Simple text paragraph layout:
-// aaaa aaaa
-//
-// bbb bb
-// bbb bb
-//
-// - list
-// list line2
-//
-// - listn
-//
-// ccc
-//
-// @todo{Add formatting to wrap paragraphs. This requires some
-// hoops as the current indentation routines are not prepared
-// for additional block being inserted. It might be possible
-// to do in 2 steps (indenting/wrapping)}
-//
+void PlainTextEditor::unCommentSelection()
+{
+ Utils::unCommentSelection(this, m_commentDefinition);
+}
-void PlainTextEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar)
+void PlainTextEditor::setFontSettings(const FontSettings &fs)
+{
+ BaseTextEditor::setFontSettings(fs);
+
+ if (baseTextDocument()->syntaxHighlighter()) {
+ Highlighter *highlighter =
+ static_cast<Highlighter *>(baseTextDocument()->syntaxHighlighter());
+
+ highlighter->configureFormat(Highlighter::VisualWhitespace, fs.toTextCharFormat(
+ QLatin1String(Constants::C_VISUAL_WHITESPACE)));
+ highlighter->configureFormat(Highlighter::Keyword, fs.toTextCharFormat(
+ QLatin1String(Constants::C_KEYWORD)));
+ highlighter->configureFormat(Highlighter::DataType, fs.toTextCharFormat(
+ QLatin1String(Constants::C_TYPE)));
+ highlighter->configureFormat(Highlighter::Comment, fs.toTextCharFormat(
+ QLatin1String(Constants::C_COMMENT)));
+ // Using C_NUMBER for all kinds of numbers.
+ highlighter->configureFormat(Highlighter::Decimal, fs.toTextCharFormat(
+ QLatin1String(Constants::C_NUMBER)));
+ highlighter->configureFormat(Highlighter::BaseN, fs.toTextCharFormat(
+ QLatin1String(Constants::C_NUMBER)));
+ highlighter->configureFormat(Highlighter::Float, fs.toTextCharFormat(
+ QLatin1String(Constants::C_NUMBER)));
+ // Using C_STRING for strings and chars.
+ highlighter->configureFormat(Highlighter::Char, fs.toTextCharFormat(
+ QLatin1String(Constants::C_STRING)));
+ highlighter->configureFormat(Highlighter::String, fs.toTextCharFormat(
+ QLatin1String(Constants::C_STRING)));
+
+ // Creator does not have corresponding formats for the following ones. Implement them?
+ // For now I will leave hardcoded values.
+ QTextCharFormat format;
+ format.setForeground(Qt::blue);
+ highlighter->configureFormat(Highlighter::Others, format);
+ format.setForeground(Qt::red);
+ highlighter->configureFormat(Highlighter::Alert, format);
+ format.setForeground(Qt::darkBlue);
+ highlighter->configureFormat(Highlighter::Function, format);
+ format.setForeground(Qt::darkGray);
+ highlighter->configureFormat(Highlighter::RegionMarker, format);
+ format.setForeground(Qt::darkRed);
+ highlighter->configureFormat(Highlighter::Error, format);
+
+ highlighter->rehighlight();
+ }
+}
+
+void PlainTextEditor::fileChanged()
{
- Q_UNUSED(typedChar)
-
- // At beginning: Leave as is.
- if (block == doc->begin())
- return;
-
- const QTextBlock previous = block.previous();
- const QString previousText = previous.text();
- // Empty line indicates a start of a new paragraph. Leave as is.
- if (previousText.isEmpty() || previousText.trimmed().isEmpty())
- return;
-
- // Just use previous line.
- // Skip blank characters when determining the indentation
- int i = 0;
- while (i < previousText.size()) {
- if (!previousText.at(i).isSpace()) {
- const TextEditor::TabSettings &ts = tabSettings();
- ts.indentLine(block, ts.columnAt(previousText, i));
- break;
+ configure(Core::ICore::instance()->mimeDatabase()->findByFile(file()->fileName()));
+}
+
+void PlainTextEditor::configure(const Core::MimeType &mimeType)
+{
+ Highlighter *highlighter = new Highlighter();
+ baseTextDocument()->setSyntaxHighlighter(highlighter);
+ m_isMissingSyntaxDefinition = true;
+
+ QString definitionId;
+ if (!mimeType.isNull()) {
+ const QString &type = mimeType.type();
+ setMimeType(type);
+
+ definitionId = Manager::instance()->definitionIdByMimeType(type);
+ if (definitionId.isEmpty())
+ definitionId = findDefinitionId(mimeType, true);
+ }
+
+ if (!definitionId.isEmpty()) {
+ const QSharedPointer<HighlightDefinition> &definition =
+ Manager::instance()->definition(definitionId);
+ if (!definition.isNull()) {
+ highlighter->setDefaultContext(definition->initialContext());
+
+ m_commentDefinition.setAfterWhiteSpaces(definition->isCommentAfterWhiteSpaces());
+ m_commentDefinition.setSingleLine(definition->singleLineComment());
+ m_commentDefinition.setMultiLineStart(definition->multiLineCommentStart());
+ m_commentDefinition.setMultiLineEnd(definition->multiLineCommentEnd());
+
+ m_isMissingSyntaxDefinition = false;
}
- ++i;
+ } else if (file()) {
+ const QString &fileName = file()->fileName();
+ if (TextEditorSettings::instance()->highlighterSettings().isIgnoredFilePattern(fileName))
+ m_isMissingSyntaxDefinition = false;
}
+
+ setFontSettings(TextEditorSettings::instance()->fontSettings());
+
+ // @todo: Indentation specification through the definition files is not really being used
+ // because Kate recommends to configure indentation through another feature. Maybe we should
+ // provide something similar in Creator? For now, only normal indentation is supported.
+ m_indenter.reset(new NormalIndenter);
+}
+
+bool PlainTextEditor::isMissingSyntaxDefinition() const
+{
+ return m_isMissingSyntaxDefinition;
+}
+
+QString PlainTextEditor::findDefinitionId(const Core::MimeType &mimeType,
+ bool considerParents) const
+{
+ QString definitionId = Manager::instance()->definitionIdByAnyMimeType(mimeType.aliases());
+ if (definitionId.isEmpty() && considerParents) {
+ definitionId = Manager::instance()->definitionIdByAnyMimeType(mimeType.subClassesOf());
+ if (definitionId.isEmpty()) {
+ foreach (const QString &parent, mimeType.subClassesOf()) {
+ const Core::MimeType &parentMimeType =
+ Core::ICore::instance()->mimeDatabase()->findByType(parent);
+ definitionId = findDefinitionId(parentMimeType, considerParents);
+ }
+ }
+ }
+ return definitionId;
+}
+
+void PlainTextEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar)
+{
+ m_indenter->indentBlock(doc, block, typedChar, tabSettings());
}
#include "basetexteditor.h"
+#include <utils/uncommentselection.h>
+
#include <QtCore/QList>
+#include <QtCore/QScopedPointer>
+
+namespace Core {
+class MimeType;
+}
namespace TextEditor {
class PlainTextEditor;
+class Indenter;
class TEXTEDITOR_EXPORT PlainTextEditorEditable : public BaseTextEditorEditable
{
+ Q_OBJECT
public:
PlainTextEditorEditable(PlainTextEditor *);
QList<int> context() const;
public:
PlainTextEditor(QWidget *parent);
+ ~PlainTextEditor();
+
+ void configure(const Core::MimeType &mimeType);
+ bool isMissingSyntaxDefinition() const;
+
+public slots:
+ virtual void unCommentSelection();
+ virtual void setFontSettings(const FontSettings &fs);
+
+private slots:
+ void fileChanged();
protected:
- virtual BaseTextEditorEditable *createEditableInterface() { return new PlainTextEditorEditable(this); }
- // Indent a text block based on previous line.
+ virtual BaseTextEditorEditable *createEditableInterface() { return new PlainTextEditorEditable(this); }
virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
+
+private:
+ QString findDefinitionId(const Core::MimeType &mimeType, bool considerParents) const;
+
+ bool m_isMissingSyntaxDefinition;
+ Utils::CommentDefinition m_commentDefinition;
+ QScopedPointer<Indenter> m_indenter;
};
} // namespace TextEditor
#include "texteditorconstants.h"
#include "texteditorplugin.h"
#include "texteditoractionhandler.h"
+#include "texteditorsettings.h"
+#include "manager.h"
+#include "highlightersettings.h"
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h>
+#include <QDebug>
+
using namespace TextEditor;
using namespace TextEditor::Internal;
{
m_actionHandler = new TextEditorActionHandler(
QLatin1String(TextEditor::Constants::C_TEXTEDITOR),
- TextEditorActionHandler::Format);
- m_mimeTypes << QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT)
- << QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_XML);
+ TextEditorActionHandler::Format |
+ TextEditorActionHandler::UnCommentSelection);
+ m_mimeTypes << QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT);
+
+ connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)),
+ this, SLOT(updateEditorInfoBar(Core::IEditor*)));
}
PlainTextEditorFactory::~PlainTextEditorFactory()
return rc->editableInterface();
}
+void PlainTextEditorFactory::updateEditorInfoBar(Core::IEditor *editor)
+{
+ PlainTextEditorEditable *editorEditable = qobject_cast<PlainTextEditorEditable *>(editor);
+ if (editorEditable) {
+ PlainTextEditor *textEditor = static_cast<PlainTextEditor *>(editorEditable->editor());
+ if (textEditor->isMissingSyntaxDefinition() &&
+ TextEditorSettings::instance()->highlighterSettings().alertWhenNoDefinition()) {
+ Core::EditorManager::instance()->showEditorInfoBar(
+ Constants::INFO_SYNTAX_DEFINITION,
+ tr("A highlight definition was not found for this file. Would you like to try to find one?"),
+ tr("Show highlighter options"),
+ Manager::instance(),
+ SLOT(showGenericHighlighterOptions()));
+ }
+ } else {
+ Core::EditorManager::instance()->hideEditorInfoBar(Constants::INFO_SYNTAX_DEFINITION);
+ }
+}
+
+void PlainTextEditorFactory::addMimeType(const QString &type)
+{
+ m_mimeTypes.append(type);
+}
+
QStringList PlainTextEditorFactory::mimeTypes() const
{
return m_mimeTypes;
PlainTextEditorFactory(QObject *parent = 0);
virtual ~PlainTextEditorFactory();
+ void addMimeType(const QString &type);
virtual QStringList mimeTypes() const;
//Core::IEditorFactory
QString id() const;
TextEditor::TextEditorActionHandler *actionHandler() const { return m_actionHandler; }
+private slots:
+ void updateEditorInfoBar(Core::IEditor *editor);
+
private:
QStringList m_mimeTypes;
TextEditor::TextEditorActionHandler *m_actionHandler;
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "quickfix.h"
+#include "basetexteditor.h"
+
+#include <coreplugin/ifile.h>
+
+#include <QtGui/QApplication>
+#include <QtGui/QTextBlock>
+
+#include <QtCore/QDebug>
+
+using TextEditor::RefactoringChanges;
+using TextEditor::QuickFixOperation;
+using TextEditor::QuickFixCollector;
+
+QuickFixOperation::QuickFixOperation(TextEditor::BaseTextEditor *editor)
+ : _editor(editor)
+{
+}
+
+QuickFixOperation::~QuickFixOperation()
+{
+}
+
+TextEditor::BaseTextEditor *QuickFixOperation::editor() const
+{
+ return _editor;
+}
+
+QTextCursor QuickFixOperation::textCursor() const
+{
+ return _textCursor;
+}
+
+void QuickFixOperation::setTextCursor(const QTextCursor &cursor)
+{
+ _textCursor = cursor;
+}
+
+int QuickFixOperation::selectionStart() const
+{
+ return _textCursor.selectionStart();
+}
+
+int QuickFixOperation::selectionEnd() const
+{
+ return _textCursor.selectionEnd();
+}
+
+int QuickFixOperation::position(int line, int column) const
+{
+ QTextDocument *doc = editor()->document();
+ return doc->findBlockByNumber(line - 1).position() + column - 1;
+}
+
+QChar QuickFixOperation::charAt(int offset) const
+{
+ QTextDocument *doc = _textCursor.document();
+ return doc->characterAt(offset);
+}
+
+QString QuickFixOperation::textOf(int start, int end) const
+{
+ QTextCursor tc = _textCursor;
+ tc.setPosition(start);
+ tc.setPosition(end, QTextCursor::KeepAnchor);
+ return tc.selectedText();
+}
+
+TextEditor::RefactoringChanges::Range QuickFixOperation::range(int start, int end)
+{
+ return TextEditor::RefactoringChanges::Range(start, end);
+}
+
+void QuickFixOperation::perform()
+{
+ createChanges();
+ apply();
+}
+
+QuickFixCollector::QuickFixCollector()
+ : _editable(0)
+{ }
+
+QuickFixCollector::~QuickFixCollector()
+{ }
+
+TextEditor::ITextEditable *QuickFixCollector::editor() const
+{ return _editable; }
+
+int QuickFixCollector::startPosition() const
+{ return _editable->position(); }
+
+bool QuickFixCollector::triggersCompletion(TextEditor::ITextEditable *)
+{ return false; }
+
+int QuickFixCollector::startCompletion(TextEditor::ITextEditable *editable)
+{
+ Q_ASSERT(editable != 0);
+
+ _editable = editable;
+
+ if (TextEditor::QuickFixState *state = initializeCompletion(editable)) {
+ TextEditor::BaseTextEditor *editor = qobject_cast<TextEditor::BaseTextEditor *>(editable->widget());
+ Q_ASSERT(editor != 0);
+
+ const QList<TextEditor::QuickFixOperation::Ptr> quickFixOperations = this->quickFixOperations(editor);
+ QMap<int, QList<TextEditor::QuickFixOperation::Ptr> > matchedOps;
+
+ foreach (TextEditor::QuickFixOperation::Ptr op, quickFixOperations) {
+ op->setTextCursor(editor->textCursor());
+ int priority = op->match(state);
+ if (priority != -1)
+ matchedOps[priority].append(op);
+ }
+
+ QMapIterator<int, QList<TextEditor::QuickFixOperation::Ptr> > it(matchedOps);
+ it.toBack();
+ if (it.hasPrevious()) {
+ it.previous();
+ _quickFixes = it.value();
+ }
+
+ delete state;
+
+ if (! _quickFixes.isEmpty())
+ return editable->position();
+ }
+
+ return -1;
+}
+
+void QuickFixCollector::completions(QList<TextEditor::CompletionItem> *quickFixItems)
+{
+ for (int i = 0; i < _quickFixes.size(); ++i) {
+ TextEditor::QuickFixOperation::Ptr op = _quickFixes.at(i);
+
+ TextEditor::CompletionItem item(this);
+ item.text = op->description();
+ item.data = QVariant::fromValue(i);
+ quickFixItems->append(item);
+ }
+}
+
+void QuickFixCollector::complete(const TextEditor::CompletionItem &item)
+{
+ const int index = item.data.toInt();
+
+ if (index < _quickFixes.size()) {
+ TextEditor::QuickFixOperation::Ptr quickFix = _quickFixes.at(index);
+ quickFix->perform();
+ }
+}
+
+void QuickFixCollector::cleanup()
+{
+ _quickFixes.clear();
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef TEXTEDITORQUICKFIX_H
+#define TEXTEDITORQUICKFIX_H
+
+#include "texteditor_global.h"
+#include "icompletioncollector.h"
+
+#include <texteditor/refactoringchanges.h>
+#include <utils/changeset.h>
+
+#include <QtCore/QSharedPointer>
+#include <QtGui/QTextCursor>
+
+namespace TextEditor {
+
+class BaseTextEditor;
+class QuickFixOperation;
+
+class TEXTEDITOR_EXPORT QuickFixState
+{
+ Q_DISABLE_COPY(QuickFixState)
+
+public:
+ QuickFixState() {}
+ virtual ~QuickFixState() {}
+};
+
+class TEXTEDITOR_EXPORT QuickFixOperation
+{
+ Q_DISABLE_COPY(QuickFixOperation)
+
+public:
+ typedef QSharedPointer<QuickFixOperation> Ptr;
+
+public:
+ QuickFixOperation(TextEditor::BaseTextEditor *editor);
+ virtual ~QuickFixOperation();
+
+ virtual QString description() const = 0;
+ virtual void createChanges() = 0;
+
+ virtual int match(QuickFixState *state) = 0;
+
+ void perform();
+
+ TextEditor::BaseTextEditor *editor() const;
+
+ QTextCursor textCursor() const;
+ void setTextCursor(const QTextCursor &cursor);
+
+ int selectionStart() const;
+ int selectionEnd() const;
+
+ int position(int line, int column) const;
+
+ QChar charAt(int offset) const;
+ QString textOf(int start, int end) const;
+
+ static TextEditor::RefactoringChanges::Range range(int start, int end);
+
+protected:
+ virtual void apply() = 0;
+ virtual TextEditor::RefactoringChanges *refactoringChanges() const = 0;
+
+private:
+ TextEditor::BaseTextEditor *_editor;
+ QTextCursor _textCursor;
+};
+
+
+class TEXTEDITOR_EXPORT QuickFixCollector: public TextEditor::IQuickFixCollector
+{
+ Q_OBJECT
+
+public:
+ QuickFixCollector();
+ virtual ~QuickFixCollector();
+
+ QList<TextEditor::QuickFixOperation::Ptr> quickFixes() const { return _quickFixes; }
+
+ virtual TextEditor::ITextEditable *editor() const;
+ virtual int startPosition() const;
+ virtual bool triggersCompletion(TextEditor::ITextEditable *editor);
+ virtual int startCompletion(TextEditor::ITextEditable *editor);
+ virtual void completions(QList<TextEditor::CompletionItem> *completions);
+ virtual void complete(const TextEditor::CompletionItem &item);
+ virtual void cleanup();
+
+ virtual TextEditor::QuickFixState *initializeCompletion(TextEditor::ITextEditable *editable) = 0;
+ virtual QList<TextEditor::QuickFixOperation::Ptr> quickFixOperations(TextEditor::BaseTextEditor *editor) const = 0;
+
+private:
+ TextEditor::ITextEditable *_editable;
+ QList<TextEditor::QuickFixOperation::Ptr> _quickFixes;
+};
+
+} // end of namespace TextEditor
+
+#endif // TEXTEDITORQUICKFIX_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "refactoringchanges.h"
+
+#include <coreplugin/editormanager/editormanager.h>
+#include <extensionsystem/pluginmanager.h>
+
+#include <QtCore/QFile>
+#include <QtCore/QSet>
+#include <QtGui/QTextBlock>
+
+using namespace TextEditor;
+
+RefactoringChanges::~RefactoringChanges()
+{}
+
+void RefactoringChanges::createFile(const QString &fileName, const QString &contents)
+{
+ m_contentsByCreatedFile.insert(fileName, contents);
+}
+
+void RefactoringChanges::changeFile(const QString &fileName, const Utils::ChangeSet &changeSet)
+{
+ m_changesByFile.insert(fileName, changeSet);
+}
+
+void RefactoringChanges::reindent(const QString &fileName, const Range &range)
+{
+ m_indentRangesByFile[fileName].append(range);
+}
+
+QStringList RefactoringChanges::apply()
+{
+ QSet<QString> changed;
+
+ { // create files
+ foreach (const QString &fileName, m_contentsByCreatedFile.keys()) {
+ BaseTextEditor *editor = editorForNewFile(fileName);
+ if (editor == 0)
+ continue;
+
+ QTextCursor tc = editor->textCursor();
+ tc.beginEditBlock();
+ tc.setPosition(0);
+ tc.insertText(m_contentsByCreatedFile.value(fileName));
+
+ foreach (const Range &range, m_indentRangesByFile.value(fileName, QList<Range>())) {
+ QTextCursor indentCursor = editor->textCursor();
+ indentCursor.setPosition(range.begin);
+ indentCursor.setPosition(range.end, QTextCursor::KeepAnchor);
+ editor->indentInsertedText(indentCursor);
+ }
+
+ tc.endEditBlock();
+ changed.insert(fileName);
+ }
+ }
+
+ { // change and indent files
+ foreach (const QString &fileName, m_changesByFile.keys()) {
+ BaseTextEditor *editor = editorForFile(fileName, true);
+ if (editor == 0)
+ continue;
+
+ QTextCursor tc = editor->textCursor();
+ tc.beginEditBlock();
+
+ typedef QPair<QTextCursor, QTextCursor> CursorPair;
+ QList<CursorPair> cursorPairs;
+ foreach (const Range &range, m_indentRangesByFile.value(fileName, QList<Range>())) {
+ QTextCursor start = editor->textCursor();
+ QTextCursor end = editor->textCursor();
+ start.setPosition(range.begin);
+ end.setPosition(range.end);
+ cursorPairs.append(qMakePair(start, end));
+ }
+
+ QTextCursor changeSetCursor = editor->textCursor();
+ Utils::ChangeSet changeSet = m_changesByFile[fileName];
+ changeSet.apply(&changeSetCursor);
+
+ foreach (const CursorPair &cursorPair, cursorPairs) {
+ QTextCursor indentCursor = cursorPair.first;
+ indentCursor.setPosition(cursorPair.second.position(),
+ QTextCursor::KeepAnchor);
+ editor->indentInsertedText(indentCursor);
+ }
+
+ tc.endEditBlock();
+ changed.insert(fileName);
+ }
+ }
+
+ { // Indent files which are not changed
+ foreach (const QString &fileName, m_indentRangesByFile.keys()) {
+ BaseTextEditor *editor = editorForFile(fileName);
+
+ if (editor == 0)
+ continue;
+
+ if (changed.contains(fileName))
+ continue;
+
+ QTextCursor tc = editor->textCursor();
+ tc.beginEditBlock();
+
+ foreach (const Range &range, m_indentRangesByFile.value(fileName, QList<Range>())) {
+ QTextCursor indentCursor = editor->textCursor();
+ indentCursor.setPosition(range.begin);
+ indentCursor.setPosition(range.end, QTextCursor::KeepAnchor);
+ editor->indentInsertedText(indentCursor);
+ }
+
+ tc.endEditBlock();
+ changed.insert(fileName);
+ }
+ }
+
+ { // Delete files
+ // ###
+ }
+
+ return changed.toList();
+}
+
+int RefactoringChanges::positionInFile(const QString &fileName, int line, int column) const
+{
+ if (BaseTextEditor *editor = editorForFile(fileName)) {
+ return editor->document()->findBlockByNumber(line).position() + column;
+ } else {
+ return -1;
+ }
+}
+
+BaseTextEditor *RefactoringChanges::editorForFile(const QString &fileName,
+ bool openIfClosed)
+{
+ Core::EditorManager *editorManager = Core::EditorManager::instance();
+
+ const QList<Core::IEditor *> editors = editorManager->editorsForFileName(fileName);
+ foreach (Core::IEditor *editor, editors) {
+ BaseTextEditor *textEditor = qobject_cast<BaseTextEditor *>(editor->widget());
+ if (textEditor != 0)
+ return textEditor;
+ }
+
+ if (!openIfClosed)
+ return 0;
+
+ Core::IEditor *editor = editorManager->openEditor(fileName, QString(),
+ Core::EditorManager::NoActivate | Core::EditorManager::IgnoreNavigationHistory | Core::EditorManager::NoModeSwitch);
+ return qobject_cast<BaseTextEditor *>(editor->widget());
+}
+
+BaseTextEditor *RefactoringChanges::editorForNewFile(const QString &fileName)
+{
+ QFile f(fileName);
+ if (f.exists())
+ return 0;
+ if (!f.open(QIODevice::Append))
+ return 0;
+ f.close();
+ return editorForFile(fileName, true);
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef REFACTORINGCHANGES_H
+#define REFACTORINGCHANGES_H
+
+#include <utils/changeset.h>
+#include <texteditor/basetexteditor.h>
+#include <texteditor/texteditor_global.h>
+
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+
+namespace TextEditor {
+
+class TEXTEDITOR_EXPORT RefactoringChanges
+{
+public:
+ struct Range {
+ Range()
+ : begin(0)
+ , end(0)
+ {}
+ Range(int beginPosition, int endPosition)
+ : begin(beginPosition)
+ , end(endPosition)
+ {}
+
+ bool isNull() const
+ { return begin == 0 || end == 0; }
+
+ int begin;
+ int end;
+ };
+
+public:
+ virtual ~RefactoringChanges();
+
+ void createFile(const QString &fileName, const QString &contents);
+ void changeFile(const QString &fileName, const Utils::ChangeSet &changeSet);
+// TODO:
+// void deleteFile(const QString &fileName);
+
+ void reindent(const QString &fileName, const Range &range);
+
+ virtual QStringList apply();
+
+ int positionInFile(const QString &fileName, int line, int column = 0) const;
+
+ static BaseTextEditor *editorForFile(const QString &fileName,
+ bool openIfClosed = false);
+ static BaseTextEditor *editorForNewFile(const QString &fileName);
+
+private:
+ QMap<QString, QString> m_contentsByCreatedFile;
+ QMap<QString, Utils::ChangeSet> m_changesByFile;
+ QMap<QString, QList<Range> > m_indentRangesByFile;
+};
+
+} // namespace TextEditor
+
+#endif // REFACTORINGCHANGES_H
TEMPLATE = lib
TARGET = TextEditor
DEFINES += TEXTEDITOR_LIBRARY
+QT += xml network
include(../../qtcreatorplugin.pri)
include(texteditor_dependencies.pri)
+INCLUDEPATH += generichighlighter
+DEPENDPATH += generichighlighter
SOURCES += texteditorplugin.cpp \
textfilewizard.cpp \
plaintexteditor.cpp \
texteditoroverlay.cpp \
texteditoroptionspage.cpp \
basetextdocumentlayout.cpp \
- completionsettings.cpp
+ completionsettings.cpp \
+ normalindenter.cpp \
+ indenter.cpp \
+ quickfix.cpp \
+ generichighlighter/itemdata.cpp \
+ generichighlighter/specificrules.cpp \
+ generichighlighter/rule.cpp \
+ generichighlighter/dynamicrule.cpp \
+ generichighlighter/context.cpp \
+ generichighlighter/includerulesinstruction.cpp \
+ generichighlighter/progressdata.cpp \
+ generichighlighter/keywordlist.cpp \
+ generichighlighter/highlightdefinition.cpp \
+ generichighlighter/highlighter.cpp \
+ generichighlighter/manager.cpp \
+ generichighlighter/highlightdefinitionhandler.cpp \
+ generichighlighter/highlightersettingspage.cpp \
+ generichighlighter/highlightersettings.cpp \
+ generichighlighter/managedefinitionsdialog.cpp \
+ generichighlighter/highlightdefinitionmetadata.cpp \
+ generichighlighter/definitiondownloader.cpp \
+ refactoringchanges.cpp
HEADERS += texteditorplugin.h \
textfilewizard.h \
texteditoroverlay.h \
texteditoroptionspage.h \
basetextdocumentlayout.h \
- completionsettings.h
-
+ completionsettings.h \
+ normalindenter.h \
+ indenter.h \
+ quickfix.h \
+ generichighlighter/reuse.h \
+ generichighlighter/itemdata.h \
+ generichighlighter/specificrules.h \
+ generichighlighter/rule.h \
+ generichighlighter/reuse.h \
+ generichighlighter/dynamicrule.h \
+ generichighlighter/context.h \
+ generichighlighter/includerulesinstruction.h \
+ generichighlighter/progressdata.h \
+ generichighlighter/keywordlist.h \
+ generichighlighter/highlighterexception.h \
+ generichighlighter/highlightdefinition.h \
+ generichighlighter/highlighter.h \
+ generichighlighter/manager.h \
+ generichighlighter/highlightdefinitionhandler.h \
+ generichighlighter/highlightersettingspage.h \
+ generichighlighter/highlightersettings.h \
+ generichighlighter/managedefinitionsdialog.h \
+ generichighlighter/highlightdefinitionmetadata.h \
+ generichighlighter/definitiondownloader.h \
+ refactoringchanges.h
FORMS += behaviorsettingspage.ui \
displaysettingspage.ui \
fontsettingspage.ui \
- colorschemeedit.ui
+ colorschemeedit.ui \
+ generichighlighter/highlightersettingspage.ui \
+ generichighlighter/managedefinitionsdialog.ui
RESOURCES += texteditor.qrc
OTHER_FILES += TextEditor.pluginspec TextEditor.mimetypes.xml
m_cleanWhitespaceAction(0),
m_textWrappingAction(0),
m_unCommentSelectionAction(0),
- m_unCollapseAllAction(0),
- m_collapseAction(0),
- m_expandAction(0),
+ m_unfoldAllAction(0),
+ m_foldAction(0),
+ m_unfoldAction(0),
m_cutLineAction(0),
m_deleteLineAction(0),
m_selectEncodingAction(0),
command = am->registerAction(m_deleteLineAction, Constants::DELETE_LINE, m_contextId);
connect(m_deleteLineAction, SIGNAL(triggered()), this, SLOT(deleteLine()));
- m_collapseAction = new QAction(tr("Collapse"), this);
- command = am->registerAction(m_collapseAction, Constants::COLLAPSE, m_contextId);
+ m_foldAction = new QAction(tr("Fold"), this);
+ command = am->registerAction(m_foldAction, Constants::FOLD, m_contextId);
command->setDefaultKeySequence(QKeySequence(tr("Ctrl+<")));
- connect(m_collapseAction, SIGNAL(triggered()), this, SLOT(collapse()));
+ connect(m_foldAction, SIGNAL(triggered()), this, SLOT(fold()));
advancedMenu->addAction(command, Core::Constants::G_EDIT_COLLAPSING);
- m_expandAction = new QAction(tr("Expand"), this);
- command = am->registerAction(m_expandAction, Constants::EXPAND, m_contextId);
+ m_unfoldAction = new QAction(tr("Unfold"), this);
+ command = am->registerAction(m_unfoldAction, Constants::UNFOLD, m_contextId);
command->setDefaultKeySequence(QKeySequence(tr("Ctrl+>")));
- connect(m_expandAction, SIGNAL(triggered()), this, SLOT(expand()));
+ connect(m_unfoldAction, SIGNAL(triggered()), this, SLOT(unfold()));
advancedMenu->addAction(command, Core::Constants::G_EDIT_COLLAPSING);
- m_unCollapseAllAction = new QAction(tr("(Un)&Collapse All"), this);
- command = am->registerAction(m_unCollapseAllAction, Constants::UN_COLLAPSE_ALL, m_contextId);
- connect(m_unCollapseAllAction, SIGNAL(triggered()), this, SLOT(unCollapseAll()));
+ m_unfoldAllAction = new QAction(tr("(Un)&Collapse All"), this);
+ command = am->registerAction(m_unfoldAllAction, Constants::UNFOLD_ALL, m_contextId);
+ connect(m_unfoldAllAction, SIGNAL(triggered()), this, SLOT(unfoldAll()));
advancedMenu->addAction(command, Core::Constants::G_EDIT_COLLAPSING);
m_increaseFontSizeAction = new QAction(tr("Increase Font Size"), this);
command->setDefaultKeySequence(QKeySequence(tr("Ctrl+J")));
connect(m_joinLinesAction, SIGNAL(triggered()), this, SLOT(joinLines()));
+ m_insertLineAboveAction = new QAction(tr("Insert Line Above Current Line"), this);
+ command = am->registerAction(m_insertLineAboveAction, Constants::INSERT_LINE_ABOVE, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+Return")));
+ connect(m_insertLineAboveAction, SIGNAL(triggered()), this, SLOT(insertLineAbove()));
+
+ m_insertLineBelowAction = new QAction(tr("Insert Line Below Current Line"), this);
+ command = am->registerAction(m_insertLineBelowAction, Constants::INSERT_LINE_BELOW, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Return")));
+ connect(m_insertLineBelowAction, SIGNAL(triggered()), this, SLOT(insertLineBelow()));
QAction *a = 0;
a = new QAction(tr("Goto Line Start"), this);
m_moveLineDownAction->setEnabled(um != ReadOnlyMode);
m_formatAction->setEnabled((m_optionalActions & Format));
- m_unCollapseAllAction->setEnabled((m_optionalActions & UnCollapseAll));
+ m_unfoldAllAction->setEnabled((m_optionalActions & UnCollapseAll));
m_visualizeWhitespaceAction->setChecked(m_currentEditor->displaySettings().m_visualizeWhitespace);
if (m_textWrappingAction) {
m_textWrappingAction->setChecked(m_currentEditor->displaySettings().m_textWrapping);
FUNCTION(unCommentSelection)
FUNCTION(cutLine)
FUNCTION(deleteLine)
-FUNCTION(unCollapseAll)
-FUNCTION(collapse)
-FUNCTION(expand)
+FUNCTION(unfoldAll)
+FUNCTION(fold)
+FUNCTION(unfold)
FUNCTION2(increaseFontSize, zoomIn)
FUNCTION2(decreaseFontSize, zoomOut)
FUNCTION2(resetFontSize, zoomReset)
FUNCTION(copyLineUp)
FUNCTION(copyLineDown)
FUNCTION(joinLines)
+FUNCTION(insertLineAbove)
+FUNCTION(insertLineBelow)
FUNCTION(gotoLineStart)
FUNCTION(gotoLineStartWithSelection)
void cleanWhitespace();
void setTextWrapping(bool);
void unCommentSelection();
- void unCollapseAll();
- void collapse();
- void expand();
+ void unfoldAll();
+ void fold();
+ void unfold();
void cutLine();
void deleteLine();
void selectEncoding();
void copyLineUp();
void copyLineDown();
void joinLines();
+ void insertLineAbove();
+ void insertLineBelow();
void updateCurrentEditor(Core::IEditor *editor);
void gotoLineStart();
QAction *m_cleanWhitespaceAction;
QAction *m_textWrappingAction;
QAction *m_unCommentSelectionAction;
- QAction *m_unCollapseAllAction;
- QAction *m_collapseAction;
- QAction *m_expandAction;
+ QAction *m_unfoldAllAction;
+ QAction *m_foldAction;
+ QAction *m_unfoldAction;
QAction *m_cutLineAction;
QAction *m_deleteLineAction;
QAction *m_selectEncodingAction;
QAction *m_copyLineUpAction;
QAction *m_copyLineDownAction;
QAction *m_joinLinesAction;
+ QAction *m_insertLineAboveAction;
+ QAction *m_insertLineBelowAction;
uint m_optionalActions;
QPointer<BaseTextEditor> m_currentEditor;
const char * const TEXT_WRAPPING = "TextEditor.TextWrapping";
const char * const UN_COMMENT_SELECTION = "TextEditor.UnCommentSelection";
const char * const REFORMAT = "TextEditor.Reformat";
-const char * const COLLAPSE = "TextEditor.Collapse";
-const char * const EXPAND = "TextEditor.Expand";
-const char * const UN_COLLAPSE_ALL = "TextEditor.UnCollapseAll";
+const char * const FOLD = "TextEditor.Fold";
+const char * const UNFOLD = "TextEditor.Unfold";
+const char * const UNFOLD_ALL = "TextEditor.UnCollapseAll";
const char * const AUTO_INDENT_SELECTION = "TextEditor.AutoIndentSelection";
const char * const INCREASE_FONT_SIZE = "TextEditor.IncreaseFontSize";
const char * const DECREASE_FONT_SIZE = "TextEditor.DecreaseFontSize";
const char * const COPY_LINE_UP = "TextEditor.CopyLineUp";
const char * const COPY_LINE_DOWN = "TextEditor.CopyLineDown";
const char * const JOIN_LINES = "TextEditor.JoinLines";
+const char * const INSERT_LINE_ABOVE = "TextEditor.InsertLineAboveCurrentLine";
+const char * const INSERT_LINE_BELOW = "TextEditor.InsertLineBelowCurrentLine";
const char * const CUT_LINE = "TextEditor.CutLine";
const char * const DELETE_LINE = "TextEditor.DeleteLine";
const char * const DELETE_WORD = "TextEditor.DeleteWord";
const char * const GOTO_PREVIOUS_WORD_WITH_SELECTION = "TextEditor.GotoPreviousWordWithSelection";
const char * const GOTO_NEXT_WORD_WITH_SELECTION = "TextEditor.GotoNextWordWithSelection";
const char * const C_TEXTEDITOR_MIMETYPE_TEXT = "text/plain";
-const char * const C_TEXTEDITOR_MIMETYPE_XML = "application/xml";
-
+const char * const INFO_SYNTAX_DEFINITION = "TextEditor.InfoSyntaxDefinition";
+const char * const TASK_DOWNLOAD = "TextEditor.Task.Download";
// Text color and style categories
const char * const C_TEXT = "Text";
const char * const TEXT_EDITOR_SETTINGS_CATEGORY = "C.TextEditor";
const char * const TEXT_EDITOR_SETTINGS_CATEGORY_ICON = ":/core/images/category_texteditor.png";
const char * const TEXT_EDITOR_SETTINGS_TR_CATEGORY = QT_TRANSLATE_NOOP("TextEditor", "Text Editor");
+const char * const TEXT_EDITOR_FONT_SETTINGS = "A.FontSettings";
+const char * const TEXT_EDITOR_BEHAVIOR_SETTINGS = "B.BehaviourSettings";
+const char * const TEXT_EDITOR_DISPLAY_SETTINGS = "D.DisplaySettings";
+const char * const TEXT_EDITOR_HIGHLIGHTER_SETTINGS = "E.HighlighterSettings";
} // namespace Constants
} // namespace TextEditor
#include "plaintexteditorfactory.h"
#include "plaintexteditor.h"
#include "storagesettings.h"
+#include "manager.h"
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
quickFixCommand->setDefaultKeySequence(QKeySequence(tr("Alt+Return")));
connect(quickFixShortcut, SIGNAL(activated()), this, SLOT(invokeQuickFix()));
+ // Generic highlighter.
+ connect(Core::ICore::instance(), SIGNAL(coreOpened()),
+ Manager::instance(), SLOT(registerMimeTypes()));
+
return true;
}
void initializeEditor(PlainTextEditor *editor);
+ PlainTextEditorFactory *editorFactory() { return m_editorFactory; }
LineNumberFilter *lineNumberFilter() { return m_lineNumberFilter; }
private slots:
#include "storagesettings.h"
#include "tabsettings.h"
#include "texteditorplugin.h"
+#include "highlightersettingspage.h"
#include <extensionsystem/pluginmanager.h>
#include <coreplugin/icore.h>
FontSettingsPage *m_fontSettingsPage;
BehaviorSettingsPage *m_behaviorSettingsPage;
DisplaySettingsPage *m_displaySettingsPage;
+ HighlighterSettingsPage *m_highlighterSettingsPage;
CompletionSettings m_completionSettings;
formatDescriptions.append(FormatDescription(QLatin1String(C_DIFF_LOCATION), tr("Diff Location"), Qt::blue));
m_d->m_fontSettingsPage = new FontSettingsPage(formatDescriptions,
- QLatin1String("A.FontSettings"),
+ QLatin1String(Constants::TEXT_EDITOR_FONT_SETTINGS),
this);
pm->addObject(m_d->m_fontSettingsPage);
// Add the GUI used to configure the tab, storage and interaction settings
TextEditor::BehaviorSettingsPageParameters behaviorSettingsPageParameters;
- behaviorSettingsPageParameters.id = QLatin1String("B.BehaviourSettings");
+ behaviorSettingsPageParameters.id = QLatin1String(Constants::TEXT_EDITOR_BEHAVIOR_SETTINGS);
behaviorSettingsPageParameters.displayName = tr("Behavior");
behaviorSettingsPageParameters.settingsPrefix = QLatin1String("text");
m_d->m_behaviorSettingsPage = new BehaviorSettingsPage(behaviorSettingsPageParameters, this);
pm->addObject(m_d->m_behaviorSettingsPage);
TextEditor::DisplaySettingsPageParameters displaySettingsPageParameters;
- displaySettingsPageParameters.id = QLatin1String("D.DisplaySettings"),
+ displaySettingsPageParameters.id = QLatin1String(Constants::TEXT_EDITOR_DISPLAY_SETTINGS),
displaySettingsPageParameters.displayName = tr("Display");
displaySettingsPageParameters.settingsPrefix = QLatin1String("text");
m_d->m_displaySettingsPage = new DisplaySettingsPage(displaySettingsPageParameters, this);
pm->addObject(m_d->m_displaySettingsPage);
+ m_d->m_highlighterSettingsPage =
+ new HighlighterSettingsPage(QLatin1String(Constants::TEXT_EDITOR_HIGHLIGHTER_SETTINGS), this);
+ pm->addObject(m_d->m_highlighterSettingsPage);
+
connect(m_d->m_fontSettingsPage, SIGNAL(changed(TextEditor::FontSettings)),
this, SIGNAL(fontSettingsChanged(TextEditor::FontSettings)));
connect(m_d->m_behaviorSettingsPage, SIGNAL(tabSettingsChanged(TextEditor::TabSettings)),
pm->removeObject(m_d->m_fontSettingsPage);
pm->removeObject(m_d->m_behaviorSettingsPage);
pm->removeObject(m_d->m_displaySettingsPage);
+ pm->removeObject(m_d->m_highlighterSettingsPage);
delete m_d;
return m_d->m_completionSettings;
}
+const HighlighterSettings &TextEditorSettings::highlighterSettings() const
+{
+ return m_d->m_highlighterSettingsPage->highlighterSettings();
+}
+
void TextEditorSettings::setCompletionSettings(const TextEditor::CompletionSettings &settings)
{
if (m_d->m_completionSettings == settings)
namespace TextEditor {
class BaseTextEditor;
-class BehaviorSettingsPage;
-class DisplaySettingsPage;
-class FontSettingsPage;
class FontSettings;
struct TabSettings;
struct StorageSettings;
struct BehaviorSettings;
struct DisplaySettings;
struct CompletionSettings;
+class HighlighterSettings;
namespace Internal {
class TextEditorSettingsPrivate;
const BehaviorSettings &behaviorSettings() const;
const DisplaySettings &displaySettings() const;
const CompletionSettings &completionSettings() const;
+ const HighlighterSettings &highlighterSettings() const;
void setCompletionSettings(const TextEditor::CompletionSettings &);
-<plugin name="VCSBase" version="2.0.80" compatVersion="2.0.80">
+<plugin name="VCSBase" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Version Control System Base Plugin</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
- <dependency name="TextEditor" version="2.0.80"/>
- <dependency name="ProjectExplorer" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
+ <dependency name="TextEditor" version="2.1.80"/>
+ <dependency name="ProjectExplorer" version="2.1.80"/>
</dependencyList>
</plugin>
#include "checkoutjobs.h"
+#include <vcsbaseplugin.h>
+
#include <QtCore/QDebug>
#include <utils/synchronousprocess.h>
ProcessCheckoutJobPrivate(const QString &binary,
const QStringList &args,
const QString &workingDirectory,
- const QStringList &env);
+ QProcessEnvironment env);
- QProcess process;
+ QSharedPointer<QProcess> process;
const QString binary;
const QStringList args;
};
+// Use a terminal-less process to suppress SSH prompts.
+static inline QSharedPointer<QProcess> createProcess()
+{
+ unsigned flags = 0;
+ if (VCSBasePlugin::isSshPromptConfigured())
+ flags = Utils::SynchronousProcess::UnixTerminalDisabled;
+ return Utils::SynchronousProcess::createProcess(flags);
+}
+
ProcessCheckoutJobPrivate::ProcessCheckoutJobPrivate(const QString &b,
const QStringList &a,
const QString &workingDirectory,
- const QStringList &env) :
+ QProcessEnvironment processEnv) :
+ process(createProcess()),
binary(b),
args(a)
-{
+{
if (!workingDirectory.isEmpty())
- process.setWorkingDirectory(workingDirectory);
- if (!env.empty())
- process.setEnvironment(env);
+ process->setWorkingDirectory(workingDirectory);
+ VCSBasePlugin::setProcessEnvironment(&processEnv);
+ process->setProcessEnvironment(processEnv);
}
ProcessCheckoutJob::ProcessCheckoutJob(const QString &binary,
const QStringList &args,
const QString &workingDirectory,
- const QStringList &env,
+ const QProcessEnvironment &env,
QObject *parent) :
AbstractCheckoutJob(parent),
d(new ProcessCheckoutJobPrivate(binary, args, workingDirectory, env))
{
if (debug)
qDebug() << "ProcessCheckoutJob" << binary << args << workingDirectory;
- connect(&d->process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(slotError(QProcess::ProcessError)));
- connect(&d->process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(slotFinished(int,QProcess::ExitStatus)));
- connect(&d->process, SIGNAL(readyReadStandardOutput()), this, SLOT(slotOutput()));
- d->process.setProcessChannelMode(QProcess::MergedChannels);
- d->process.closeWriteChannel();
+ connect(d->process.data(), SIGNAL(error(QProcess::ProcessError)), this, SLOT(slotError(QProcess::ProcessError)));
+ connect(d->process.data(), SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(slotFinished(int,QProcess::ExitStatus)));
+ connect(d->process.data(), SIGNAL(readyReadStandardOutput()), this, SLOT(slotOutput()));
+ d->process->setProcessChannelMode(QProcess::MergedChannels);
+ d->process->closeWriteChannel();
}
ProcessCheckoutJob::~ProcessCheckoutJob()
void ProcessCheckoutJob::slotOutput()
{
- const QByteArray data = d->process.readAllStandardOutput();
+ const QByteArray data = d->process->readAllStandardOutput();
const QString s = QString::fromLocal8Bit(data, data.endsWith('\n') ? data.size() - 1: data.size());
if (debug)
qDebug() << s;
{
switch (error) {
case QProcess::FailedToStart:
- emit failed(tr("Unable to start %1: %2").arg(d->binary, d->process.errorString()));
+ emit failed(tr("Unable to start %1: %2").arg(d->binary, d->process->errorString()));
break;
default:
- emit failed(d->process.errorString());
+ emit failed(d->process->errorString());
break;
}
}
void ProcessCheckoutJob::start()
{
- d->process.start(d->binary, d->args);
+ d->process->start(d->binary, d->args);
}
void ProcessCheckoutJob::cancel()
qDebug() << "ProcessCheckoutJob::start";
emit output(tr("Stopping..."));
- Utils::SynchronousProcess::stopProcess(d->process);
+ Utils::SynchronousProcess::stopProcess(*d->process);
}
} // namespace VCSBase
#include <QtCore/QObject>
#include <QtCore/QStringList>
#include <QtCore/QProcess>
+#include <QtCore/QProcessEnvironment>
QT_BEGIN_NAMESPACE
class QStringList;
explicit ProcessCheckoutJob(const QString &binary,
const QStringList &args,
const QString &workingDirectory = QString(),
- const QStringList &env = QStringList(),
+ const QProcessEnvironment &env = QProcessEnvironment::systemEnvironment(),
QObject *parent = 0);
virtual ~ProcessCheckoutJob();
m_ui->submitMessageCheckScriptChooser->setExpectedKind(Utils::PathChooser::Command);
m_ui->nickNameFieldsFileChooser->setExpectedKind(Utils::PathChooser::File);
m_ui->nickNameMailMapChooser->setExpectedKind(Utils::PathChooser::File);
+ m_ui->sshPromptChooser->setExpectedKind(Utils::PathChooser::Command);
}
CommonSettingsWidget::~CommonSettingsWidget()
rc.submitMessageCheckScript = m_ui->submitMessageCheckScriptChooser->path();
rc.lineWrap= m_ui->lineWrapCheckBox->isChecked();
rc.lineWrapWidth = m_ui->lineWrapSpinBox->value();
+ rc.sshPasswordPrompt = m_ui->sshPromptChooser->path();
return rc;
}
m_ui->submitMessageCheckScriptChooser->setPath(s.submitMessageCheckScript);
m_ui->lineWrapCheckBox->setChecked(s.lineWrap);
m_ui->lineWrapSpinBox->setValue(s.lineWrapWidth);
+ m_ui->sshPromptChooser->setPath(s.sshPasswordPrompt);
}
QString CommonSettingsWidget::searchKeyWordMatchString() const
<rect>
<x>0</x>
<y>0</y>
- <width>359</width>
- <height>105</height>
+ <width>338</width>
+ <height>166</height>
</rect>
</property>
- <layout class="QGridLayout" name="gridLayout">
+ <layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="lineWrapCheckBox">
<property name="text">
</property>
</widget>
</item>
- <item row="0" column="2">
+ <item row="1" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</spacer>
</item>
- <item row="1" column="0">
+ <item row="2" column="0">
<widget class="QLabel" name="submitMessageCheckScriptLabel">
<property name="toolTip">
<string>An executable which is called with the submit message in a temporary file as first argument. It should return with an exit != 0 and a message on standard error to indicate failure.</string>
</property>
</widget>
</item>
- <item row="1" column="1" colspan="2">
+ <item row="2" column="1">
<widget class="Utils::PathChooser" name="submitMessageCheckScriptChooser" native="true"/>
</item>
- <item row="2" column="0">
+ <item row="3" column="0">
<widget class="QLabel" name="nickNameMailMapLabel">
<property name="toolTip">
<string>A file listing user names and email addresses in a 4-column mailmap format:
</property>
</widget>
</item>
- <item row="2" column="1" colspan="2">
+ <item row="3" column="1">
<widget class="Utils::PathChooser" name="nickNameMailMapChooser" native="true"/>
</item>
- <item row="3" column="0">
+ <item row="4" column="0">
<widget class="QLabel" name="nickNameFieldsFileLabel">
<property name="toolTip">
<string>A simple file containing lines with field names like "Reviewed-By:" which will be added below the submit editor.</string>
</property>
</widget>
</item>
- <item row="3" column="1" colspan="2">
+ <item row="4" column="1">
<widget class="Utils::PathChooser" name="nickNameFieldsFileChooser" native="true"/>
</item>
- <item row="4" column="0" colspan="3">
+ <item row="6" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="sshPromptLabel">
+ <property name="toolTip">
+ <string>Specifies a command that is executed to graphically prompt for a password,
+should a repository require SSH-authentication (see documentation on SSH and the environment variable SSH_ASKPASS).</string>
+ </property>
+ <property name="text">
+ <string>SSH prompt command:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="Utils::PathChooser" name="sshPromptChooser" native="true"/>
+ </item>
</layout>
</widget>
<customwidgets>
#include <QtCore/QSettings>
#include <QtCore/QDebug>
-static const char *settingsGroupC = "VCS";
-static const char *nickNameMailMapKeyC = "NickNameMailMap";
-static const char *nickNameFieldListFileKeyC = "NickNameFieldListFile";
-static const char *submitMessageCheckScriptKeyC = "SubmitMessageCheckScript";
-static const char *lineWrapKeyC = "LineWrap";
-static const char *lineWrapWidthKeyC = "LineWrapWidth";
+static const char settingsGroupC[] = "VCS";
+static const char nickNameMailMapKeyC[] = "NickNameMailMap";
+static const char nickNameFieldListFileKeyC[] = "NickNameFieldListFile";
+static const char submitMessageCheckScriptKeyC[] = "SubmitMessageCheckScript";
+static const char lineWrapKeyC[] = "LineWrap";
+static const char lineWrapWidthKeyC[] = "LineWrapWidth";
+static const char sshPasswordPromptKeyC[] = "SshPasswordPrompt";
static const int lineWrapWidthDefault = 72;
static const bool lineWrapDefault = true;
+// Return default for the ssh-askpass command (default to environment)
+static inline QString sshPasswordPromptDefault()
+{
+ const QByteArray envSetting = qgetenv("SSH_ASKPASS");
+ if (!envSetting.isEmpty())
+ return QString::fromLocal8Bit(envSetting);
+#ifdef Q_OS_WIN
+ return QLatin1String("win-ssh-askpass");
+#else
+ return QLatin1String("ssh-askpass");
+#endif
+}
+
namespace VCSBase {
namespace Internal {
CommonVcsSettings::CommonVcsSettings() :
+ sshPasswordPrompt(sshPasswordPromptDefault()),
lineWrap(lineWrapDefault),
lineWrapWidth(lineWrapWidthDefault)
{
s->setValue(QLatin1String(submitMessageCheckScriptKeyC), submitMessageCheckScript);
s->setValue(QLatin1String(lineWrapKeyC), lineWrap);
s->setValue(QLatin1String(lineWrapWidthKeyC), lineWrapWidth);
+ // Do not store the default setting to avoid clobbering the environment.
+ if (sshPasswordPrompt != sshPasswordPromptDefault()) {
+ s->setValue(QLatin1String(sshPasswordPromptKeyC), sshPasswordPrompt);
+ } else {
+ s->remove(QLatin1String(sshPasswordPromptKeyC));
+ }
s->endGroup();
}
submitMessageCheckScript = s->value(QLatin1String(submitMessageCheckScriptKeyC), QString()).toString();
lineWrap = s->value(QLatin1String(lineWrapKeyC), lineWrapDefault).toBool();
lineWrapWidth = s->value(QLatin1String(lineWrapWidthKeyC), lineWrapWidthDefault).toInt();
+ sshPasswordPrompt = s->value(QLatin1String(sshPasswordPromptKeyC), sshPasswordPromptDefault()).toString();
s->endGroup();
}
&& lineWrapWidth == rhs.lineWrapWidth
&& nickNameMailMap == rhs.nickNameMailMap
&& nickNameFieldListFile == rhs.nickNameFieldListFile
- && submitMessageCheckScript == rhs.submitMessageCheckScript;
+ && submitMessageCheckScript == rhs.submitMessageCheckScript
+ && sshPasswordPrompt == rhs.sshPasswordPrompt;
}
QDebug operator<<(QDebug d,const CommonVcsSettings& s)
<< " lineWrapWidth=" << s.lineWrapWidth
<< " nickNameMailMap='" << s.nickNameMailMap
<< "' nickNameFieldListFile='" << s.nickNameFieldListFile
- << "'submitMessageCheckScript='" << s.submitMessageCheckScript << "'\n";
+ << "'submitMessageCheckScript='" << s.submitMessageCheckScript
+ << "'sshPasswordPrompt='" << s.sshPasswordPrompt
+ << "'\n";
return d;
}
QString submitMessageCheckScript;
+ // Executable run to graphically prompt for a SSH-password.
+ QString sshPasswordPrompt;
+
bool lineWrap;
int lineWrapWidth;
{
}
+void SubmitEditorFile::rename(const QString &newName)
+{
+ Q_UNUSED(newName);
+ // We can't be renamed
+ return;
+}
+
void SubmitEditorFile::setFileName(const QString name)
{
m_fileName = name;
bool save(const QString &fileName);
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
void reload(ReloadFlag flag, ChangeType type);
-
+ void rename(const QString &newName);
void setFileName(const QString name);
void setModified(bool modified = true);
// Try to locate via repository.
if (!control)
return QString();
- const QString topLevel = control->findTopLevelForDirectory(sourceDir);
- if (topLevel.isEmpty())
+ QString topLevel;
+ if (!control->managesDirectory(sourceDir, &topLevel))
return QString();
const QFileInfo topLevelFileInfo(topLevel + slash + f);
if (topLevelFileInfo.isFile())
#include <QtCore/QPointer>
#include <QtCore/QTextCodec>
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
#include <QtCore/QTime>
#include <QtCore/QPoint>
#include <QtCore/QFileInfo>
popup(false); // Pop up without focus
}
+// Helper to format arguments for log windows hiding common password
+// options.
+static inline QString formatArguments(const QStringList &args)
+{
+ const char passwordOptionC[] = "--password";
+
+ 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(passwordOptionC)) {
+ str << " ********";
+ i++;
+ }
+ }
+ return rc;
+}
+
+QString VCSBaseOutputWindow::msgExecutionLogEntry(const QString &workingDir,
+ const QString &executable,
+ const QStringList &arguments)
+{
+ const QString args = formatArguments(arguments);
+ if (workingDir.isEmpty())
+ return tr("Executing: %1 %2\n").arg(executable, args);
+ return tr("Executing in %1: %2 %3\n").
+ arg(QDir::toNativeSeparators(workingDir), executable, args);
+}
+
void VCSBaseOutputWindow::appendCommand(const QString &text)
{
d->plainTextEdit()->appendCommand(text);
}
+void VCSBaseOutputWindow::appendCommand(const QString &workingDirectory,
+ const QString &binary,
+ const QStringList &args)
+{
+ appendCommand(msgExecutionLogEntry(workingDirectory, binary, args));
+}
+
+
void VCSBaseOutputWindow::appendData(const QByteArray &data)
{
appendDataSilently(data);
QString repository() const;
+ // Helper to consistently format log entries for commands as
+ // 'Executing <dir>: <cmd> <args>'. Hides well-known password option
+ // arguments.
+ static QString msgExecutionLogEntry(const QString &workingDir,
+ const QString &executable,
+ const QStringList &arguments);
+
public slots:
void setRepository(const QString &);
void clearRepository();
// Append a command, prepended by a log time stamp. "Executing: vcs -diff"
// will result in "10:00 Executing: vcs -diff" in bold
void appendCommand(const QString &text);
+ // Append a standard-formatted entry for command execution
+ // (see msgExecutionLogEntry).
+ void appendCommand(const QString &workingDirectory,
+ const QString &binary,
+ const QStringList &args);
private:
VCSBaseOutputWindow();
#include "vcsbaseplugin.h"
#include "vcsbasesubmiteditor.h"
#include "vcsplugin.h"
+#include "commonvcssettings.h"
#include "vcsbaseoutputwindow.h"
#include "corelistener.h"
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/project.h>
#include <utils/qtcassert.h>
+#include <utils/synchronousprocess.h>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QSharedData>
#include <QtCore/QScopedPointer>
+#include <QtCore/QProcessEnvironment>
+#include <QtCore/QTextStream>
+#include <QtCore/QTextCodec>
#include <QtGui/QAction>
#include <QtGui/QMessageBox>
#include <QtGui/QFileDialog>
#include <QtGui/QMainWindow>
-enum { debug = 0, debugRepositorySearch = 0 };
+enum { debug = 0, debugRepositorySearch = 0, debugExecution = 0 };
namespace VCSBase {
return QString();
}
+// Is SSH prompt configured?
+static inline QString sshPrompt()
+{
+ return VCSBase::Internal::VCSPlugin::instance()->settings().sshPasswordPrompt;
+}
+
+bool VCSBasePlugin::isSshPromptConfigured()
+{
+ return !sshPrompt().isEmpty();
+}
+
+void VCSBasePlugin::setProcessEnvironment(QProcessEnvironment *e)
+{
+ e->insert(QLatin1String("LANG"), QString(QLatin1Char('C')));
+ const QString sshPromptBinary = sshPrompt();
+ if (!sshPromptBinary.isEmpty())
+ e->insert(QLatin1String("SSH_ASKPASS"), sshPromptBinary);
+}
+
+Utils::SynchronousProcessResponse
+ VCSBasePlugin::runVCS(const QString &workingDir,
+ const QString &binary,
+ const QStringList &arguments,
+ int timeOutMS,
+ unsigned flags,
+ QTextCodec *outputCodec /* = 0 */)
+{
+ const QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ return runVCS(workingDir, binary, arguments, timeOutMS, env,
+ flags, outputCodec);
+}
+
+Utils::SynchronousProcessResponse
+ VCSBasePlugin::runVCS(const QString &workingDir,
+ const QString &binary,
+ const QStringList &arguments,
+ int timeOutMS,
+ QProcessEnvironment env,
+ unsigned flags,
+ QTextCodec *outputCodec /* = 0 */)
+{
+ VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
+
+ if (!(flags & SuppressCommandLogging))
+ outputWindow->appendCommand(workingDir, binary, arguments);
+
+ const bool sshPromptConfigured = VCSBasePlugin::isSshPromptConfigured();
+ if (debugExecution) {
+ QDebug nsp = qDebug().nospace();
+ nsp << "VCSBasePlugin::runVCS" << workingDir << binary << arguments
+ << timeOutMS;
+ if (flags & ShowStdOutInLogWindow)
+ nsp << "stdout";
+ if (flags & SuppressStdErrInLogWindow)
+ nsp << "suppress_stderr";
+ if (flags & SuppressFailMessageInLogWindow)
+ nsp << "suppress_fail_msg";
+ if (flags & MergeOutputChannels)
+ nsp << "merge_channels";
+ if (flags & SshPasswordPrompt)
+ nsp << "ssh (" << sshPromptConfigured << ')';
+ if (flags & SuppressCommandLogging)
+ nsp << "suppress_log";
+ if (outputCodec)
+ nsp << " Codec: " << outputCodec->name();
+ }
+
+ // Run, connect stderr to the output window
+ Utils::SynchronousProcess process;
+ if (!workingDir.isEmpty())
+ process.setWorkingDirectory(workingDir);
+
+ VCSBase::VCSBasePlugin::setProcessEnvironment(&env);
+ process.setProcessEnvironment(env);
+ process.setTimeout(timeOutMS);
+ if (outputCodec)
+ process.setStdOutCodec(outputCodec);
+
+ // Suppress terminal on UNIX for ssh prompts if it is configured.
+ if (sshPromptConfigured && (flags & SshPasswordPrompt))
+ process.setFlags(Utils::SynchronousProcess::UnixTerminalDisabled);
+
+ // connect stderr to the output window if desired
+ if (flags & MergeOutputChannels) {
+ process.setProcessChannelMode(QProcess::MergedChannels);
+ } else {
+ if (!(flags & SuppressStdErrInLogWindow)) {
+ process.setStdErrBufferedSignalsEnabled(true);
+ connect(&process, SIGNAL(stdErrBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
+ }
+ }
+
+ // connect stdout to the output window if desired
+ if (flags & ShowStdOutInLogWindow) {
+ process.setStdOutBufferedSignalsEnabled(true);
+ connect(&process, SIGNAL(stdOutBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
+ }
+
+ process.setTimeOutMessageBoxEnabled(true);
+
+ // Run!
+ const Utils::SynchronousProcessResponse sp_resp = process.run(binary, arguments);
+
+ // Success/Fail message in appropriate window?
+ if (sp_resp.result == Utils::SynchronousProcessResponse::Finished) {
+ if (flags & ShowSuccessMessage)
+ outputWindow->append(sp_resp.exitMessage(binary, timeOutMS));
+ } else {
+ if (!(flags & SuppressFailMessageInLogWindow))
+ outputWindow->appendError(sp_resp.exitMessage(binary, timeOutMS));
+ }
+
+ return sp_resp;
+}
} // namespace VCSBase
#include "vcsbaseplugin.moc"
QT_BEGIN_NAMESPACE
class QAction;
+class QProcessEnvironment;
+class QTextCodec;
QT_END_NAMESPACE
+namespace Utils {
+ struct SynchronousProcessResponse;
+}
+
namespace Core {
class IVersionControl;
}
// a well known file. See implementation for gory details.
static QString findRepositoryForDirectory(const QString &dir, const QString &checkFile);
+ // Set up the environment for a version control command line call.
+ // Sets LANG to 'C' to force English (suppress LOCALE warnings)
+ // and sets up SSH graphical password prompting (note that the latter
+ // requires a terminal-less process).
+ static void setProcessEnvironment(QProcessEnvironment *e);
+ // Returns whether an SSH prompt is configured.
+ static bool isSshPromptConfigured();
+
+ // Convenience to synchronously run VCS commands
+ enum RunVCSFlags {
+ ShowStdOutInLogWindow = 0x1, // Append standard output to VCS output window.
+ MergeOutputChannels = 0x2, // see QProcess: Merge stderr/stdout.
+ SshPasswordPrompt = 0x4, // Disable terminal on UNIX to force graphical prompt.
+ SuppressStdErrInLogWindow = 0x8, // No standard error output to VCS output window.
+ SuppressFailMessageInLogWindow = 0x10, // No message VCS about failure in VCS output window.
+ SuppressCommandLogging = 0x20, // No command log entry in VCS output window.
+ ShowSuccessMessage = 0x40 // Show message about successful completion in VCS output window.
+ };
+
+ static Utils::SynchronousProcessResponse
+ runVCS(const QString &workingDir,
+ const QString &binary,
+ const QStringList &arguments,
+ int timeOutMS,
+ QProcessEnvironment env,
+ unsigned flags = 0,
+ QTextCodec *outputCodec = 0);
+
+ static Utils::SynchronousProcessResponse
+ runVCS(const QString &workingDir,
+ const QString &binary,
+ const QStringList &arguments,
+ int timeOutMS,
+ unsigned flags = 0,
+ QTextCodec *outputCodec = 0);
+
public slots:
// Convenience slot for "Delete current file" action. Prompts to
// delete the file via VCSManager.
}
QByteArray stdOutData;
QByteArray stdErrData;
- if (!Utils::SynchronousProcess::readDataFromProcess(checkProcess, 30000, &stdOutData, &stdErrData)) {
+ if (!Utils::SynchronousProcess::readDataFromProcess(checkProcess, 30000, &stdOutData, &stdErrData, false)) {
Utils::SynchronousProcess::stopProcess(checkProcess);
*errorMessage = tr("The check script '%1' timed out.").arg(checkScript);
return false;
-<plugin name="Welcome" version="2.0.80" compatVersion="2.0.80">
+<plugin name="Welcome" version="2.1.80" compatVersion="2.1.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2010 Nokia Corporation</copyright>
<license>
<description>Default Welcome Screen Plugin</description>
<url>http://qt.nokia.com</url>
<dependencyList>
- <dependency name="Core" version="2.0.80"/>
+ <dependency name="Core" version="2.1.80"/>
</dependencyList>
</plugin>
--- /dev/null
+# Try to find location of Qt private headers (see README)
+isEmpty(QT_PRIVATE_HEADERS) {
+ QT_PRIVATE_HEADERS = $$[QT_INSTALL_HEADERS]
+} else {
+ INCLUDEPATH += \
+ $${QT_PRIVATE_HEADERS} \
+ $${QT_PRIVATE_HEADERS}/QtCore \
+ $${QT_PRIVATE_HEADERS}/QtGui \
+ $${QT_PRIVATE_HEADERS}/QtScript \
+ $${QT_PRIVATE_HEADERS}/QtDeclarative
+ DEPENDPATH += \
+ $${QT_PRIVATE_HEADERS} \
+ $${QT_PRIVATE_HEADERS}/QtCore \
+ $${QT_PRIVATE_HEADERS}/QtGui \
+ $${QT_PRIVATE_HEADERS}/QtScript \
+ $${QT_PRIVATE_HEADERS}/QtDeclarative
+}
else if (dot_dot_dot_token)
return dot_dot_dot_token + 1;
- else if (base_clause_list)
- return base_clause_list->lastToken();
+ else if (base_clause_list) {
+ unsigned token = base_clause_list->lastToken();
+ if (token)
+ return token;
+ }
- else if (colon_token)
+ if (colon_token)
return colon_token + 1;
else if (name)
unsigned ObjCClassDeclarationAST::lastToken() const
{
- if (end_token) return end_token + 1;
- if (member_declaration_list) return member_declaration_list->lastToken();
- if (inst_vars_decl) return inst_vars_decl->lastToken();
- if (protocol_refs)
- return protocol_refs->lastToken();
- if (superclass)
- return superclass->lastToken();
- if (colon_token) return colon_token + 1;
+ if (end_token)
+ return end_token + 1;
+
+ if (member_declaration_list) {
+ if (unsigned token = member_declaration_list->lastToken())
+ return token;
+ }
+
+ if (inst_vars_decl) {
+ if (unsigned token = inst_vars_decl->lastToken())
+ return token;
+ }
+
+ if (protocol_refs) {
+ if (unsigned token = protocol_refs->lastToken())
+ return token;
+ }
+
+ if (superclass) {
+ if (unsigned token = superclass->lastToken())
+ return token;
+ }
+
+ if (colon_token)
+ return colon_token + 1;
+
if (rparen_token)
return rparen_token + 1;
- if (category_name)
- return category_name->lastToken();
+
+ if (category_name) {
+ if (unsigned token = category_name->lastToken())
+ return token;
+ }
+
if (lparen_token)
return lparen_token + 1;
- if (class_name) return class_name->lastToken();
+
+ if (class_name) {
+ if (unsigned token = class_name->lastToken())
+ return token;
+ }
if (interface_token)
return interface_token + 1;
- else
- return implementation_token + 1;
+
+ return implementation_token + 1;
}
unsigned ObjCProtocolDeclarationAST::firstToken() const
if (end_token)
return end_token + 1;
- else if (member_declaration_list)
- return member_declaration_list->lastToken();
-
- else if (protocol_refs)
- return protocol_refs->lastToken();
-
- else if (name)
- return name->lastToken();
-
- else if (attribute_list)
- return attribute_list->lastToken();
+ if (member_declaration_list) {
+ if (unsigned token = member_declaration_list->lastToken())
+ return token;
+ }
+
+ if (protocol_refs) {
+ if (unsigned token = protocol_refs->lastToken())
+ return token;
+ }
+
+ if (name) {
+ if (unsigned token = name->lastToken())
+ return token;
+ }
+
+ if (attribute_list) {
+ if (unsigned token = attribute_list->lastToken())
+ return token;
+ }
return protocol_token + 1;
}
class TypenameArgument;
class Function;
class Namespace;
+class NamespaceAlias;
class BaseClass;
class Block;
class Class;
symbol->setTemplateParameters(_templateParameters);
_templateParameters = 0;
}
+
if (ty.isDeprecated())
symbol->setDeprecated(true);
+ if (ty.isUnavailable())
+ symbol->setUnavailable(true);
+
+ if (ty.isFriend())
+ symbol->setStorage(Symbol::Friend);
_scope->enterSymbol(symbol);
return false;
Function *fun = 0;
if (declTy && 0 != (fun = declTy->asFunctionType())) {
- fun->setSourceLocation(location);
+ fun->setSourceLocation(location, translationUnit());
fun->setScope(_scope);
fun->setName(name);
fun->setMethodKey(semantic()->currentMethodKey());
fun->setVirtual(ty.isVirtual());
if (ty.isDeprecated())
fun->setDeprecated(true);
+ if (ty.isUnavailable())
+ fun->setUnavailable(true);
if (isQ_SIGNAL)
fun->setMethodKey(Function::SignalMethod);
else if (isQ_SLOT)
Declaration *symbol = control()->newDeclaration(location, name);
symbol->setStartOffset(tokenAt(ast->firstToken()).offset);
- symbol->setEndOffset(tokenAt(ast->lastToken()).offset);
+ symbol->setEndOffset(tokenAt(ast->lastToken() - 1).end());
symbol->setType(declTy);
if (declTy.isDeprecated())
symbol->setDeprecated(true);
+ if (declTy.isUnavailable())
+ symbol->setUnavailable(true);
if (_templateParameters && it == ast->declarator_list) {
symbol->setTemplateParameters(_templateParameters);
if (ty.isDeprecated())
symbol->setDeprecated(true);
+ if (ty.isUnavailable())
+ symbol->setUnavailable(true);
if (it->value && it->value->initializer) {
FullySpecifiedType initTy = semantic()->check(it->value->initializer, _scope);
Declaration *symbol = control()->newDeclaration(location, name);
symbol->setStartOffset(tokenAt(ast->firstToken()).offset);
- symbol->setEndOffset(tokenAt(ast->lastToken()).offset);
+ symbol->setEndOffset(tokenAt(ast->lastToken() - 1).end());
symbol->setType(declTy);
_scope->enterSymbol(symbol);
fun->setVirtual(ty.isVirtual());
if (ty.isDeprecated())
fun->setDeprecated(true);
+ if (ty.isUnavailable())
+ fun->setUnavailable(true);
fun->setStartOffset(tokenAt(ast->firstToken()).offset);
- fun->setEndOffset(tokenAt(ast->lastToken()).offset);
+ fun->setEndOffset(tokenAt(ast->lastToken() - 1).end());
if (ast->declarator)
- fun->setSourceLocation(ast->declarator->firstToken());
+ fun->setSourceLocation(ast->declarator->firstToken(), translationUnit());
fun->setName(name);
fun->setTemplateParameters(_templateParameters);
fun->setVisibility(semantic()->currentVisibility());
Namespace *ns = control()->newNamespace(sourceLocation, namespaceName);
ns->setStartOffset(tokenAt(ast->firstToken()).offset);
- ns->setEndOffset(tokenAt(ast->lastToken()).offset);
+ ns->setEndOffset(tokenAt(ast->lastToken() - 1).end());
ast->symbol = ns;
_scope->enterSymbol(ns);
semantic()->check(ast->linkage_body, ns->members()); // ### we'll do the merge later.
return false;
}
-bool CheckDeclaration::visit(NamespaceAliasDefinitionAST *)
+bool CheckDeclaration::visit(NamespaceAliasDefinitionAST *ast)
{
+ const Name *name = 0;
+
+ if (const Identifier *id = identifier(ast->namespace_name_token))
+ name = control()->nameId(id);
+
+ unsigned sourceLocation = ast->firstToken();
+
+ if (ast->namespace_name_token)
+ sourceLocation = ast->namespace_name_token;
+
+ const Name *namespaceName = semantic()->check(ast->name, _scope);
+
+ NamespaceAlias *namespaceAlias = control()->newNamespaceAlias(sourceLocation, name);
+ namespaceAlias->setNamespaceName(namespaceName);
+ namespaceAlias->setStartOffset(tokenAt(ast->firstToken()).offset);
+ namespaceAlias->setEndOffset(tokenAt(ast->lastToken() - 1).end());
+ //ast->symbol = namespaceAlias;
+ _scope->enterSymbol(namespaceAlias);
+
return false;
}
const Name *protocolName = semantic()->check(it->value, _scope);
ObjCForwardProtocolDeclaration *fwdProtocol = control()->newObjCForwardProtocolDeclaration(sourceLocation, protocolName);
fwdProtocol->setStartOffset(tokenAt(ast->firstToken()).offset);
- fwdProtocol->setEndOffset(tokenAt(ast->lastToken()).offset);
+ fwdProtocol->setEndOffset(tokenAt(ast->lastToken() - 1).end());
_scope->enterSymbol(fwdProtocol);
const Name *protocolName = semantic()->check(ast->name, _scope);
ObjCProtocol *protocol = control()->newObjCProtocol(sourceLocation, protocolName);
protocol->setStartOffset(tokenAt(ast->firstToken()).offset);
- protocol->setEndOffset(tokenAt(ast->lastToken()).offset);
+ protocol->setEndOffset(tokenAt(ast->lastToken() - 1).end());
if (ast->protocol_refs && ast->protocol_refs->identifier_list) {
for (NameListAST *iter = ast->protocol_refs->identifier_list; iter; iter = iter->next) {
const Name *className = semantic()->check(it->value, _scope);
ObjCForwardClassDeclaration *fwdClass = control()->newObjCForwardClassDeclaration(sourceLocation, className);
fwdClass->setStartOffset(tokenAt(ast->firstToken()).offset);
- fwdClass->setEndOffset(tokenAt(ast->lastToken()).offset);
+ fwdClass->setEndOffset(tokenAt(ast->lastToken() - 1).end());
_scope->enterSymbol(fwdClass);
const Name *className = semantic()->check(ast->class_name, _scope);
ObjCClass *klass = control()->newObjCClass(sourceLocation, className);
klass->setStartOffset(tokenAt(ast->firstToken()).offset);
- klass->setEndOffset(tokenAt(ast->lastToken()).offset);
+ klass->setEndOffset(tokenAt(ast->lastToken() - 1).end());
ast->symbol = klass;
klass->setInterface(ast->interface_token != 0);
}
symbol->setStartOffset(tokenAt(ast->firstToken()).offset);
- symbol->setEndOffset(tokenAt(ast->lastToken()).offset);
+ symbol->setEndOffset(tokenAt(ast->lastToken() - 1).end());
symbol->setVisibility(semantic()->currentObjCVisibility());
if (ty.isDeprecated())
symbol->setDeprecated(true);
+ if (ty.isUnavailable())
+ symbol->setUnavailable(true);
_scope->enterSymbol(symbol);
const char *declName)
{
for (NameListAST *iter = nameListAst; iter; iter = iter->next) {
- if (!iter)
- continue;
const Name *name = semantic()->check(iter->value, _scope);
if (!name)
bool CheckName::visit(ObjCSelectorAST *ast)
{
std::vector<const Name *> names;
+ bool hasArgs = false;
for (ObjCSelectorArgumentListAST *it = ast->selector_argument_list; it; it = it->next) {
if (it->value->name_token) {
const Identifier *id = control()->findOrInsertIdentifier(spell(it->value->name_token));
const NameId *nameId = control()->nameId(id);
names.push_back(nameId);
+
+ if (!hasArgs && it->value->colon_token)
+ hasArgs = true;
} else {
// we have an incomplete name due, probably due to error recovery. So, back out completely
return false;
}
if (!names.empty()) {
- _name = control()->selectorNameId(&names[0], names.size(), true);
+ _name = control()->selectorNameId(&names[0], names.size(), hasArgs);
ast->name = _name;
}
const Name *className = semantic()->check(ast->name, _scope);
Class *klass = control()->newClass(sourceLocation, className);
klass->setStartOffset(tokenAt(ast->firstToken()).offset);
- klass->setEndOffset(tokenAt(ast->lastToken()).offset);
+ klass->setEndOffset(tokenAt(ast->lastToken() - 1).end());
ast->symbol = klass;
unsigned classKey = tokenKind(ast->classkey_token);
if (classKey == T_CLASS)
if (_fullySpecifiedType.isDeprecated())
klass->setDeprecated(true);
+ if (_fullySpecifiedType.isUnavailable())
+ klass->setUnavailable(true);
for (BaseSpecifierListAST *it = ast->base_clause_list; it; it = it->next) {
BaseSpecifierAST *base = it->value;
const Name *name = semantic()->check(ast->name, _scope);
Enum *e = control()->newEnum(sourceLocation, name);
e->setStartOffset(tokenAt(ast->firstToken()).offset);
- e->setEndOffset(tokenAt(ast->lastToken()).offset);
+ e->setEndOffset(tokenAt(ast->lastToken() - 1).end());
e->setVisibility(semantic()->currentVisibility());
_scope->enterSymbol(e);
_fullySpecifiedType.setType(e);
bool CheckSpecifier::visit(AttributeAST *ast)
{
if (ast->identifier_token) {
- if (identifier(ast->identifier_token) == control()->deprecatedId())
+ const Identifier *id = identifier(ast->identifier_token);
+
+ if (id == control()->deprecatedId())
_fullySpecifiedType.setDeprecated(true);
+ else if (id == control()->unavailableId())
+ _fullySpecifiedType.setUnavailable(true);
}
return false;
}
{
Block *block = control()->newBlock(ast->lbrace_token);
block->setStartOffset(tokenAt(ast->firstToken()).offset);
- block->setEndOffset(tokenAt(ast->lastToken()).offset);
+ block->setEndOffset(tokenAt(ast->lastToken() - 1).end());
ast->symbol = block;
_scope->enterSymbol(block);
Scope *previousScope = switchScope(block->members());
{
// translationUnit()->warning(ast->firstToken(),
// "ambiguous expression or declaration statement");
- if (ast->declaration) {
- semantic()->check(ast->declaration, _scope);
- _exprType = FullySpecifiedType();
- } else {
- _exprType = semantic()->check(ast->expression, _scope);
- }
+
+ semantic()->check(ast->declaration, _scope);
+ _exprType = semantic()->check(ast->expression, _scope);
+
return false;
}
{
Block *block = control()->newBlock(firstToken);
block->setStartOffset(tokenAt(firstToken).offset);
- block->setEndOffset(tokenAt(lastToken).offset);
+ block->setEndOffset(tokenAt(lastToken - 1).end());
symbol = block;
_scope->enterSymbol(block);
Scope *previousScope = switchScope(block->members());
{
Block *block = control()->newBlock(ast->for_token);
block->setStartOffset(tokenAt(ast->firstToken()).offset);
- block->setEndOffset(tokenAt(ast->lastToken()).offset);
+ block->setEndOffset(tokenAt(ast->lastToken() - 1).end());
ast->symbol = block;
_scope->enterSymbol(block);
Scope *previousScope = switchScope(block->members());
{
Block *block = control()->newBlock(ast->if_token);
block->setStartOffset(tokenAt(ast->firstToken()).offset);
- block->setEndOffset(tokenAt(ast->lastToken()).offset);
+ block->setEndOffset(tokenAt(ast->lastToken() - 1).end());
ast->symbol = block;
_scope->enterSymbol(block);
Scope *previousScope = switchScope(block->members());
{
Block *block = control()->newBlock(ast->switch_token);
block->setStartOffset(tokenAt(ast->firstToken()).offset);
- block->setEndOffset(tokenAt(ast->lastToken()).offset);
+ block->setEndOffset(tokenAt(ast->lastToken() - 1).end());
ast->symbol = block;
_scope->enterSymbol(block);
Scope *previousScope = switchScope(block->members());
{
Block *block = control()->newBlock(ast->catch_token);
block->setStartOffset(tokenAt(ast->firstToken()).offset);
- block->setEndOffset(tokenAt(ast->lastToken()).offset);
+ block->setEndOffset(tokenAt(ast->lastToken() - 1).end());
ast->symbol = block;
_scope->enterSymbol(block);
Scope *previousScope = switchScope(block->members());
{
Block *block = control()->newBlock(ast->while_token);
block->setStartOffset(tokenAt(ast->firstToken()).offset);
- block->setEndOffset(tokenAt(ast->lastToken()).offset);
+ block->setEndOffset(tokenAt(ast->lastToken() - 1).end());
ast->symbol = block;
_scope->enterSymbol(block);
Scope *previousScope = switchScope(block->members());
{
public:
Data(Control *control)
- : control(control),
- translationUnit(0),
- diagnosticClient(0)
+ : control(control)
+ , translationUnit(0)
+ , diagnosticClient(0)
+ , deprecatedId(0)
+ , unavailableId(0)
+ , objcGetterId(0)
+ , objcSetterId(0)
+ , objcReadwriteId(0)
+ , objcReadonlyId(0)
+ , objcAssignId(0)
+ , objcRetainId(0)
+ , objcCopyId(0)
+ , objcNonatomicId(0)
{}
~Data()
return ns;
}
+ NamespaceAlias *newNamespaceAlias(unsigned sourceLocation, const Name *name)
+ {
+ NamespaceAlias *ns = new NamespaceAlias(translationUnit,
+ sourceLocation, name);
+ symbols.push_back(ns);
+ return ns;
+ }
+
UsingNamespaceDirective *newUsingNamespaceDirective(unsigned sourceLocation, const Name *name)
{
UsingNamespaceDirective *u = new UsingNamespaceDirective(translationUnit,
std::vector<Symbol *> symbols;
const Identifier *deprecatedId;
+ const Identifier *unavailableId;
// ObjC context keywords:
const Identifier *objcGetterId;
const Identifier *objcSetterId;
d = new Data(this);
d->deprecatedId = findOrInsertIdentifier("deprecated");
+ d->unavailableId = findOrInsertIdentifier("unavailable");
d->objcGetterId = findOrInsertIdentifier("getter");
d->objcSetterId = findOrInsertIdentifier("setter");
Namespace *Control::newNamespace(unsigned sourceLocation, const Name *name)
{ return d->newNamespace(sourceLocation, name); }
+NamespaceAlias *Control::newNamespaceAlias(unsigned sourceLocation, const Name *name)
+{ return d->newNamespaceAlias(sourceLocation, name); }
+
BaseClass *Control::newBaseClass(unsigned sourceLocation, const Name *name)
{ return d->newBaseClass(sourceLocation, name); }
const Identifier *Control::deprecatedId() const
{ return d->deprecatedId; }
+const Identifier *Control::unavailableId() const
+{ return d->unavailableId; }
+
const Identifier *Control::objcGetterId() const
{ return d->objcGetterId; }
/// Creates a new Namespace symbol.
Namespace *newNamespace(unsigned sourceLocation, const Name *name = 0);
+ /// Creates a new Namespace symbol.
+ NamespaceAlias *newNamespaceAlias(unsigned sourceLocation, const Name *name = 0);
+
/// Creates a new BaseClass symbol.
BaseClass *newBaseClass(unsigned sourceLocation, const Name *name = 0);
ObjCPropertyDeclaration *newObjCPropertyDeclaration(unsigned sourceLocation, const Name *name);
const Identifier *deprecatedId() const;
+ const Identifier *unavailableId() const;
// Objective-C specific context keywords.
const Identifier *objcGetterId() const;
const Identifier *objcSetterId() const;
ty.setExplicit(false);
ty.setDeprecated(false);
+ ty.setUnavailable(false);
return ty;
}
void FullySpecifiedType::setDeprecated(bool isDeprecated)
{ f._isDeprecated = isDeprecated; }
+bool FullySpecifiedType::isUnavailable() const
+{ return f._isUnavailable; }
+
+void FullySpecifiedType::setUnavailable(bool isUnavailable)
+{ f._isUnavailable = isUnavailable; }
+
bool FullySpecifiedType::isEqualTo(const FullySpecifiedType &other) const
{
if (_flags != other._flags)
bool isDeprecated() const;
void setDeprecated(bool isDeprecated);
+ bool isUnavailable() const;
+ void setUnavailable(bool isUnavailable);
+
bool isEqualTo(const FullySpecifiedType &other) const;
Type &operator*();
// speficiers from attributes
unsigned _isDeprecated: 1;
+ unsigned _isUnavailable: 1;
};
union {
unsigned _flags;
int _blockCount;
char *_ptr;
char *_end;
- int _ccc;
enum
{
bool TemplateNameId::isEqualTo(const Name *other) const
{
+ if (! other)
+ return false;
const TemplateNameId *t = other->asTemplateNameId();
if (! t)
return false;
match(T_GREATER, &ast->greater_token);
}
- parseDeclaration(ast->declaration);
+ while (LA()) {
+ unsigned start_declaration = cursor();
+
+ ast->declaration = 0;
+ if (parseDeclaration(ast->declaration))
+ break;
+
+ _translationUnit->error(start_declaration, "expected a declaration");
+ rewind(start_declaration + 1);
+ skipUntilDeclaration();
+ }
+
node = ast;
return true;
}
match(T_RPAREN, &ast->dptr_rparen_token);
}
match(T_COMMA, &ast->comma_token);
- parseTypeSpecifier(ast->type_specifiers);
+ (void) parseTypeSpecifier(ast->type_specifiers);
parseDeclarator(ast->declarator);
match(T_RPAREN, &ast->rparen_token);
node = ast;
{
DEBUG_THIS_RULE();
+#ifdef CPLUSPLUS_WITH_CXXOX_INITIALIZER_LIST
if (_cxx0xEnabled)
return parseInitializerList0x(node);
-
-
+#endif
// ### remove me
ExpressionListAST **expression_list_ptr = &node;
if (it) {
SpecifierAST *spec = it->value;
- if (! it->next && (spec->asElaboratedTypeSpecifier() ||
- spec->asEnumSpecifier() ||
- spec->asClassSpecifier()))
+ if (spec->asElaboratedTypeSpecifier() ||
+ spec->asEnumSpecifier() ||
+ spec->asClassSpecifier()) {
+ for (it = it->next; it; it = it->next)
+ if (it->value->asAttributeSpecifier() == 0)
+ return false;
return true;
+ }
}
}
UnaryExpressionAST *ast = new (_pool) UnaryExpressionAST;
ast->unary_op_token = consumeToken();
- parseCastExpression(ast->expression);
+ (void) parseCastExpression(ast->expression);
node = ast;
return true;
}
match(T_RBRACKET, &ast->rbracket_token);
}
- parseCastExpression(ast->expression);
+ (void) parseCastExpression(ast->expression);
node = ast;
return true;
}
DEBUG_THIS_RULE();
return parseSimpleTypeSpecifier(node);
}
+
+void Parser::rewind(unsigned cursor)
+{
+ if (cursor < _translationUnit->tokenCount())
+ _tokenIndex = cursor;
+ else
+ _tokenIndex = _translationUnit->tokenCount() - 1;
+}
inline unsigned cursor() const
{ return _tokenIndex; }
- inline void rewind(unsigned cursor)
- { _tokenIndex = cursor; }
+ void rewind(unsigned cursor);
struct TemplateArgumentListEntry {
unsigned index;
return false;
}
+bool Scope::isObjCProtocolScope() const
+{
+ if (_owner)
+ return _owner->isObjCProtocol();
+ return false;
+}
+
bool Scope::isFunctionScope() const
{
Function *f = 0;
/// Returns true if this scope's owner is an ObjCClass Symbol.
bool isObjCClassScope() const;
+ /// Returns true if this scope's owner is an ObjCProtocol Symbol.
+ bool isObjCProtocolScope() const;
+
/// Returns true if this scope's owner is an ObjCMethod symbol.
bool isObjCMethodScope() const;
};
Symbol::Symbol(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name)
- : _control(translationUnit->control()),
- _sourceLocation(sourceLocation),
- _sourceOffset(0),
- _startOffset(0),
+ : _startOffset(0),
_endOffset(0),
_name(0),
_hashCode(0),
_scope(0),
_index(0),
_next(0),
- _isGenerated(false)
+ _isGenerated(false),
+ _isDeprecated(false),
+ _isUnavailable(false)
{
- setSourceLocation(sourceLocation);
+ setSourceLocation(sourceLocation, translationUnit);
setName(name);
}
Symbol::~Symbol()
{ }
-Control *Symbol::control() const
-{ return _control; }
-
-TranslationUnit *Symbol::translationUnit() const
-{ return _control->translationUnit(); }
-
void Symbol::visitSymbol(SymbolVisitor *visitor)
{
if (visitor->preVisit(this))
unsigned Symbol::sourceLocation() const
{ return _sourceLocation; }
-unsigned Symbol::sourceOffset() const
-{ return _sourceOffset; }
-
bool Symbol::isGenerated() const
{ return _isGenerated; }
void Symbol::setDeprecated(bool isDeprecated)
{ _isDeprecated = isDeprecated; }
-void Symbol::setSourceLocation(unsigned sourceLocation)
-{
- _sourceLocation = sourceLocation;
+bool Symbol::isUnavailable() const
+{ return _isUnavailable; }
- if (! _sourceLocation) {
- _isGenerated = false;
- _sourceOffset = 0;
- } else {
- TranslationUnit *unit = translationUnit();
+void Symbol::setUnavailable(bool isUnavailable)
+{ _isUnavailable = isUnavailable; }
- const Token &tk = unit->tokenAt(sourceLocation);
+void Symbol::setSourceLocation(unsigned sourceLocation, TranslationUnit *translationUnit)
+{
+ _sourceLocation = sourceLocation;
+ if (translationUnit) {
+ const Token &tk = translationUnit->tokenAt(sourceLocation);
_isGenerated = tk.f.generated;
- _sourceOffset = tk.offset;
+ translationUnit->getPosition(tk.offset, &_line, &_column, &_fileId);
+ } else {
+ _isGenerated = false;
+ _line = 0;
+ _column = 0;
+ _fileId = 0;
}
}
unsigned Symbol::line() const
{
- unsigned line = 0, column = 0;
- const StringLiteral *fileId = 0;
- translationUnit()->getPosition(_sourceOffset, &line, &column, &fileId);
- return line;
+ return _line;
}
unsigned Symbol::column() const
{
- unsigned line = 0, column = 0;
- const StringLiteral *fileId = 0;
- translationUnit()->getPosition(_sourceOffset, &line, &column, &fileId);
- return column;
+ return _column;
}
const StringLiteral *Symbol::fileId() const
{
- unsigned line = 0, column = 0;
- const StringLiteral *fileId = 0;
- translationUnit()->getPosition(_sourceOffset, &line, &column, &fileId);
- return fileId;
+ return _fileId;
}
-void Symbol::getPosition(unsigned *line, unsigned *column, const StringLiteral **fileId) const
-{ translationUnit()->getPosition(_sourceOffset, line, column, fileId); }
-
-void Symbol::getStartPosition(unsigned *line, unsigned *column, const StringLiteral **fileId) const
-{ translationUnit()->getPosition(_startOffset, line, column, fileId); }
-
-void Symbol::getEndPosition(unsigned *line, unsigned *column, const StringLiteral **fileId) const
-{ translationUnit()->getPosition(_endOffset, line, column, fileId); }
-
const char *Symbol::fileName() const
{ return fileId()->chars(); }
bool Symbol::isObjCPropertyDeclaration() const
{ return asObjCPropertyDeclaration() != 0; }
+
+void Symbol::copy(Symbol *other)
+{
+ _sourceLocation = other->_sourceLocation;
+ _startOffset = other->_startOffset;
+ _endOffset = other->_endOffset;
+ _name = other->_name;
+ _hashCode = other->_hashCode;
+ _storage = other->_storage;
+ _visibility = other->_visibility;
+ _scope = other->_scope;
+ _index = other->_index;
+ _next = other->_next;
+ _fileId = other->_fileId;
+ _line = other->_line;
+ _column = other->_column;
+
+ _isGenerated = other->_isGenerated;
+ _isDeprecated = other->_isDeprecated;
+}
/// Destroy this Symbol.
virtual ~Symbol();
- /// Returns this Symbol's Control object.
- Control *control() const;
-
/// Returns this Symbol's source location.
unsigned sourceLocation() const;
- /// Returns this Symbol's source offset.
- unsigned sourceOffset() const;
-
/// Returns this Symbol's line number.
unsigned line() const;
unsigned endOffset() const;
void setEndOffset(unsigned offset);
- void getPosition(unsigned *line, unsigned *column = 0, const StringLiteral **fileId = 0) const;
- void getStartPosition(unsigned *line, unsigned *column = 0, const StringLiteral **fileId = 0) const;
- void getEndPosition(unsigned *line, unsigned *column = 0, const StringLiteral **fileId = 0) const;
-
/// Returns this Symbol's name.
const Name *name() const;
virtual const Enum *asEnum() const { return 0; }
virtual const Function *asFunction() const { return 0; }
virtual const Namespace *asNamespace() const { return 0; }
+ virtual const NamespaceAlias *asNamespaceAlias() const { return 0; }
virtual const Class *asClass() const { return 0; }
virtual const Block *asBlock() const { return 0; }
virtual const UsingNamespaceDirective *asUsingNamespaceDirective() const { return 0; }
virtual Enum *asEnum() { return 0; }
virtual Function *asFunction() { return 0; }
virtual Namespace *asNamespace() { return 0; }
+ virtual NamespaceAlias *asNamespaceAlias() { return 0; }
virtual Class *asClass() { return 0; }
virtual Block *asBlock() { return 0; }
virtual UsingNamespaceDirective *asUsingNamespaceDirective() { return 0; }
bool isDeprecated() const;
void setDeprecated(bool isDeprecated);
+ bool isUnavailable() const;
+ void setUnavailable(bool isUnavailable);
+
Symbol *enclosingSymbol() const;
/// Returns the eclosing namespace scope.
Scope *enclosingBlockScope() const;
void setScope(Scope *scope); // ### make me private
- void setSourceLocation(unsigned sourceLocation); // ### make me private
+ void setSourceLocation(unsigned sourceLocation, TranslationUnit *translationUnit); // ### make me private
void visitSymbol(SymbolVisitor *visitor);
static void visitSymbol(Symbol *symbol, SymbolVisitor *visitor);
+ virtual void copy(Symbol *other);
+
protected:
virtual void visitSymbol0(SymbolVisitor *visitor) = 0;
- TranslationUnit *translationUnit() const;
-
private:
- Control *_control;
unsigned _sourceLocation;
- unsigned _sourceOffset;
unsigned _startOffset;
unsigned _endOffset;
const Name *_name;
Scope *_scope;
unsigned _index;
Symbol *_next;
+ const StringLiteral *_fileId;
+ unsigned _line;
+ unsigned _column;
bool _isGenerated: 1;
bool _isDeprecated: 1;
+ bool _isUnavailable: 1;
class IdentityForName;
class HashCode;
virtual bool visit(UsingNamespaceDirective *) { return true; }
virtual bool visit(UsingDeclaration *) { return true; }
+ virtual bool visit(NamespaceAlias *) { return true; }
virtual bool visit(Declaration *) { return true; }
virtual bool visit(Argument *) { return true; }
virtual bool visit(TypenameArgument *) { return true; }
void UsingNamespaceDirective::visitSymbol0(SymbolVisitor *visitor)
{ visitor->visit(this); }
+NamespaceAlias::NamespaceAlias(TranslationUnit *translationUnit,
+ unsigned sourceLocation, const Name *name)
+ : Symbol(translationUnit, sourceLocation, name), _namespaceName(0)
+{ }
+
+NamespaceAlias::~NamespaceAlias()
+{ }
+
+const Name *NamespaceAlias::namespaceName() const
+{ return _namespaceName; }
+
+void NamespaceAlias::setNamespaceName(const Name *namespaceName)
+{ _namespaceName = namespaceName; }
+
+FullySpecifiedType NamespaceAlias::type() const
+{ return FullySpecifiedType(); }
+
+void NamespaceAlias::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
+
UsingDeclaration::UsingDeclaration(TranslationUnit *translationUnit,
unsigned sourceLocation, const Name *name)
: Symbol(translationUnit, sourceLocation, name)
virtual void visitSymbol0(SymbolVisitor *visitor);
};
+class CPLUSPLUS_EXPORT NamespaceAlias: public Symbol
+{
+public:
+ NamespaceAlias(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name);
+ virtual ~NamespaceAlias();
+
+ const Name *namespaceName() const;
+ void setNamespaceName(const Name *namespaceName);
+
+ // Symbol's interface
+ virtual FullySpecifiedType type() const;
+
+ virtual const NamespaceAlias *asNamespaceAlias() const
+ { return this; }
+
+ virtual NamespaceAlias *asNamespaceAlias()
+ { return this; }
+
+protected:
+ virtual void visitSymbol0(SymbolVisitor *visitor);
+
+private:
+ const Name *_namespaceName;
+};
+
class CPLUSPLUS_EXPORT Declaration: public Symbol
{
public:
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+/*
+ This file is a self-contained interactive indenter for C++ and Qt
+ Script.
+
+ The general problem of indenting a C++ program is ill posed. On the
+ one hand, an indenter has to analyze programs written in a
+ free-form formal language that is best described in terms of
+ tokens, not characters, not lines. On the other hand, indentation
+ applies to lines and white space characters matter, and otherwise
+ the programs to indent are formally invalid in general, as they are
+ being edited.
+
+ The approach taken here works line by line. We receive a program
+ consisting of N lines or more, and we want to compute the
+ indentation appropriate for the Nth line. Lines beyond the Nth
+ lines are of no concern to us, so for simplicity we pretend the
+ program has exactly N lines and we call the Nth line the "bottom
+ line". Typically, we have to indent the bottom line when it's still
+ empty, so we concentrate our analysis on the N - 1 lines that
+ precede.
+
+ By inspecting the (N - 1)-th line, the (N - 2)-th line, ...
+ backwards, we determine the kind of the bottom line and indent it
+ accordingly.
+
+ * The bottom line is a comment line. See
+ bottomLineStartsInCComment() and
+ indentWhenBottomLineStartsInCComment().
+ * The bottom line is a continuation line. See isContinuationLine()
+ and indentForContinuationLine().
+ * The bottom line is a standalone line. See
+ indentForStandaloneLine().
+
+ Certain tokens that influence the indentation, notably braces, are
+ looked for in the lines. This is done by simple string comparison,
+ without a real tokenizer. Confusing constructs such as comments and
+ string literals are removed beforehand.
+*/
+
+#include "indenter.h"
+
+namespace SharedTools {
+
+/* qmake ignore Q_OBJECT */
+
+/*
+ The indenter avoids getting stuck in almost infinite loops by
+ imposing arbitrary limits on the number of lines it analyzes when
+ looking for a construct.
+
+ For example, the indenter never considers more than BigRoof lines
+ backwards when looking for the start of a C-style comment.
+*/
+namespace {
+ enum { SmallRoof = 40, BigRoof = 400 };
+
+/*
+ The indenter supports a few parameters:
+
+ * ppHardwareTabSize is the size of a '\t' in your favorite editor.
+ * ppIndentSize is the size of an indentation, or software tab
+ size.
+ * ppContinuationIndentSize is the extra indent for a continuation
+ line, when there is nothing to align against on the previous
+ line.
+ * ppCommentOffset is the indentation within a C-style comment,
+ when it cannot be picked up.
+ * ppIndentBraces will indent braces flush with an indented code
+ block.
+ * ppDoubleIndentBlocks do double indent of blocks so as together
+ with ppIndentBraces enabled it form some sort of GNU indenting style
+*/
+
+
+ enum { ppCommentOffset = 1 };
+}
+
+Indenter::Indenter() :
+ ppHardwareTabSize(8),
+ ppIndentSize(4),
+ ppIndentBraces(false),
+ ppContinuationIndentSize(8),
+ ppDoubleIndentBlocks(false),
+ yyLinizerState(new LinizerState),
+ yyLine(0),
+ yyBraceDepth(0),
+ yyLeftBraceFollows(0)
+{
+}
+
+Indenter::~Indenter()
+{
+ delete yyLinizerState;
+}
+
+Indenter &Indenter::instance()
+{
+ static Indenter rc;
+ return rc;
+}
+
+void Indenter::setIndentSize(int size)
+{
+ ppIndentSize = size;
+ ppContinuationIndentSize = 2 * size;
+}
+
+void Indenter::setTabSize(int size)
+{
+ ppHardwareTabSize = size;
+}
+
+void Indenter::setIndentBraces(bool indent)
+{
+ ppIndentBraces = indent;
+}
+
+void Indenter::setDoubleIndentBlocks(bool indent)
+{
+ ppDoubleIndentBlocks = indent;
+}
+
+/*
+ Returns the first non-space character in the string t, or
+ QChar::null if the string is made only of white space.
+*/
+QChar Indenter::firstNonWhiteSpace(const QString &t)
+{
+ if (const int len = t.length())
+ for (int i = 0; i < len; i++)
+ if (!t[i].isSpace())
+ return t[i];
+ return QChar::Null;
+}
+
+/*
+ Returns true if string t is made only of white space; otherwise
+ returns false.
+*/
+bool Indenter::isOnlyWhiteSpace(const QString &t)
+{
+ return t.isEmpty() || firstNonWhiteSpace(t).isNull();
+}
+
+/*
+ Assuming string t is a line, returns the column number of a given
+ index. Column numbers and index are identical for strings that don't
+ contain '\t's.
+*/
+int Indenter::columnForIndex(const QString &t, int index) const
+{
+ int col = 0;
+ if (index > t.length())
+ index = t.length();
+
+ const QChar tab = QLatin1Char('\t');
+
+ for (int i = 0; i < index; i++) {
+ if (t[i] == tab) {
+ col = ((col / ppHardwareTabSize) + 1) * ppHardwareTabSize;
+ } else {
+ col++;
+ }
+ }
+ return col;
+}
+
+/*
+ Returns the indentation size of string t.
+*/
+int Indenter::indentOfLine(const QString &t) const
+{
+ return columnForIndex(t, t.indexOf(firstNonWhiteSpace(t)));
+}
+
+/*
+ Replaces t[k] by ch, unless t[k] is '\t'. Tab characters are better
+ left alone since they break the "index equals column" rule. No
+ provisions are taken against '\n' or '\r', which shouldn't occur in
+ t anyway.
+*/
+static inline void eraseChar(QString &t, int k, QChar ch)
+{
+ if (t[k] != QLatin1Char('\t'))
+ t[k] = ch;
+}
+
+/*
+ Removes some nefast constructs from a code line and returns the
+ resulting line.
+*/
+QString Indenter::trimmedCodeLine(const QString &t)
+{
+ QString trimmed = t;
+ int k;
+
+ const QChar capitalX = QLatin1Char('X');
+ const QChar blank = QLatin1Char(' ');
+ const QChar colon = QLatin1Char(':');
+ const QChar semicolon = QLatin1Char(';');
+ /*
+ Replace character and string literals by X's, since they may
+ contain confusing characters (such as '{' and ';'). "Hello!" is
+ replaced by XXXXXXXX. The literals are rigourously of the same
+ length before and after; otherwise, we would break alignment of
+ continuation lines.
+ */
+ k = 0;
+ while ((k = m_constants.m_literal.indexIn(trimmed), k) != -1) {
+ const int matchedLength = m_constants.m_literal.matchedLength();
+ for (int i = 0; i < matchedLength ; i++)
+ eraseChar(trimmed, k + i, capitalX);
+ k += matchedLength;
+ }
+
+ /*
+ Replace inline C-style comments by spaces. Other comments are
+ handled elsewhere.
+ */
+ k = 0;
+ while ((k = m_constants.m_inlineCComment.indexIn(trimmed, k)) != -1) {
+ const int matchedLength = m_constants.m_inlineCComment.matchedLength();
+ for (int i = 0; i < matchedLength; i++)
+ eraseChar(trimmed, k + i, blank);
+ k += matchedLength;
+ }
+
+ /*
+ Replace goto and switch labels by whitespace, but be careful
+ with this case:
+
+ foo1: bar1;
+ bar2;
+ */
+ while (trimmed.lastIndexOf(colon) != -1 && m_constants.m_label.indexIn(trimmed) != -1) {
+ const QString cap1 = m_constants.m_label.cap(1);
+ const int pos1 = m_constants.m_label.pos(1);
+ int stop = cap1.length();
+
+ if (pos1 + stop < trimmed.length() && ppIndentSize < stop)
+ stop = ppIndentSize;
+
+ int i = 0;
+ while (i < stop) {
+ eraseChar(trimmed, pos1 + i, blank );
+ i++;
+ }
+ while (i < cap1.length()) {
+ eraseChar(trimmed, pos1 + i,semicolon);
+ i++;
+ }
+ }
+
+ /*
+ Remove C++-style comments.
+ */
+ k = trimmed.indexOf(m_constants.m_slashSlash);
+ if (k != -1)
+ trimmed.truncate(k);
+
+ return trimmed;
+}
+
+/*
+ Returns '(' if the last parenthesis is opening, ')' if it is
+ closing, and QChar::null if there are no parentheses in t.
+*/
+static inline QChar lastParen(const QString &t)
+{
+
+ const QChar opening = QLatin1Char('(');
+ const QChar closing = QLatin1Char(')');
+
+
+ int i = t.length();
+ while (i > 0) {
+ i--;
+ const QChar c = t[i];
+ if (c == opening || c == closing)
+ return c;
+ }
+ return QChar::Null;
+}
+
+/*
+ Returns true if typedIn the same as okayCh or is null; otherwise
+ returns false.
+*/
+static inline bool okay(QChar typedIn, QChar okayCh)
+{
+ return typedIn == QChar::Null || typedIn == okayCh;
+}
+
+
+/*
+ Saves and restores the state of the global linizer. This enables
+ backtracking.
+*/
+#define YY_SAVE() \
+LinizerState savedState = *yyLinizerState
+#define YY_RESTORE() \
+ *yyLinizerState = savedState
+
+ /*
+ Advances to the previous line in yyProgram and update yyLine
+ accordingly. yyLine is cleaned from comments and other damageable
+ constructs. Empty lines are skipped.
+*/
+ bool Indenter::readLine()
+ {
+ int k;
+
+ const QChar openingBrace = QLatin1Char('{');
+ const QChar closingBrace = QLatin1Char('}');
+ const QChar blank = QLatin1Char(' ');
+ const QChar hash = QLatin1Char('#');
+
+ yyLinizerState->leftBraceFollows =
+ (firstNonWhiteSpace(yyLinizerState->line) == openingBrace );
+
+ do {
+ if (yyLinizerState->iter == yyProgramBegin) {
+ yyLinizerState->line = QString::null;
+ return false;
+ }
+
+ --yyLinizerState->iter;
+ yyLinizerState->line = *yyLinizerState->iter;
+
+ yyLinizerState->line = trimmedCodeLine(yyLinizerState->line);
+
+ /*
+ Remove C-style comments that span multiple lines. If the
+ bottom line starts in a C-style comment, we are not aware
+ of that and eventually yyLine will contain a slash-aster.
+
+ Notice that both if's can be executed, since
+ yyLinizerState->inCComment is potentially set to false in
+ the first if. The order of the if's is also important.
+ */
+
+ if (yyLinizerState->inCComment) {
+
+ k = yyLinizerState->line.indexOf(m_constants.m_slashAster);
+ if (k == -1) {
+ yyLinizerState->line = QString::null;
+ } else {
+ yyLinizerState->line.truncate(k);
+ yyLinizerState->inCComment = false;
+ }
+ }
+
+ if (!yyLinizerState->inCComment) {
+ k = yyLinizerState->line.indexOf(m_constants.m_asterSlash);
+ if (k != -1) {
+ for (int i = 0; i < k + 2; i++)
+ eraseChar(yyLinizerState->line, i, blank);
+ yyLinizerState->inCComment = true;
+ }
+ }
+
+ /*
+ Remove preprocessor directives.
+ */
+ k = 0;
+ while (k < yyLinizerState->line.length()) {
+ QChar ch = yyLinizerState->line[k];
+ if (ch == hash) {
+ yyLinizerState->line = QString::null;
+ } else if (!ch.isSpace()) {
+ break;
+ }
+ k++;
+ }
+
+ /*
+ Remove trailing spaces.
+ */
+ k = yyLinizerState->line.length();
+ while (k > 0 && yyLinizerState->line[k - 1].isSpace())
+ k--;
+ yyLinizerState->line.truncate(k);
+
+ /*
+ '}' increment the brace depth and '{' decrements it and not
+ the other way around, as we are parsing backwards.
+ */
+ yyLinizerState->braceDepth +=
+ yyLinizerState->line.count(closingBrace ) - yyLinizerState->line.count(openingBrace );
+
+ /*
+ We use a dirty trick for
+
+ } else ...
+
+ We don't count the '}' yet, so that it's more or less
+ equivalent to the friendly construct
+
+ }
+ else ...
+ */
+ if (yyLinizerState->pendingRightBrace)
+ yyLinizerState->braceDepth++;
+ yyLinizerState->pendingRightBrace =
+ (m_constants.m_braceX.indexIn(yyLinizerState->line) == 0);
+ if (yyLinizerState->pendingRightBrace)
+ yyLinizerState->braceDepth--;
+ } while (yyLinizerState->line.isEmpty());
+
+ return true;
+}
+
+/*
+ Resets the linizer to its initial state, with yyLine containing the
+ line above the bottom line of the program.
+*/
+void Indenter::startLinizer()
+{
+ yyLinizerState->braceDepth = 0;
+ yyLinizerState->inCComment = false;
+ yyLinizerState->pendingRightBrace = false;
+
+ yyLine = &yyLinizerState->line;
+ yyBraceDepth = &yyLinizerState->braceDepth;
+ yyLeftBraceFollows = &yyLinizerState->leftBraceFollows;
+
+ yyLinizerState->iter = yyProgramEnd;
+ --yyLinizerState->iter;
+ yyLinizerState->line = *yyLinizerState->iter;
+ readLine();
+}
+
+/*
+ Returns true if the start of the bottom line of yyProgram (and
+ potentially the whole line) is part of a C-style comment; otherwise
+ returns false.
+*/
+bool Indenter::bottomLineStartsInCComment()
+{
+ /*
+ We could use the linizer here, but that would slow us down
+ terribly. We are better to trim only the code lines we need.
+ */
+ Iterator p = yyProgramEnd;
+ --p; // skip bottom line
+
+ for (int i = 0; i < BigRoof; i++) {
+ if (p == yyProgramBegin)
+ return false;
+ --p;
+
+ if ((*p).contains(m_constants.m_slashAster) || (*p).contains(m_constants.m_asterSlash)) {
+ QString trimmed = trimmedCodeLine(*p);
+
+ if (trimmed.contains(m_constants.m_slashAster)) {
+ return true;
+ } else if (trimmed.contains(m_constants.m_asterSlash)) {
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+/*
+ Returns the recommended indent for the bottom line of yyProgram
+ assuming that it starts in a C-style comment, a condition that is
+ tested elsewhere.
+
+ Essentially, we're trying to align against some text on the previous
+ line.
+*/
+int Indenter::indentWhenBottomLineStartsInCComment() const
+{
+ int k = yyLine->lastIndexOf(m_constants.m_slashAster);
+ if (k == -1) {
+ /*
+ We found a normal text line in a comment. Align the
+ bottom line with the text on this line.
+ */
+ return indentOfLine(*yyLine);
+ } else {
+ /*
+ The C-style comment starts on this line. If there is
+ text on the same line, align with it. Otherwise, align
+ with the slash-aster plus a given offset.
+ */
+ const int indent = columnForIndex(*yyLine, k);
+ k += 2;
+ while (k < yyLine->length()) {
+ if (!(*yyLine)[k].isSpace())
+ return columnForIndex(*yyLine, k);
+ k++;
+ }
+ return indent + ppCommentOffset;
+ }
+}
+
+/*
+ A function called match...() modifies the linizer state. If it
+ returns true, yyLine is the top line of the matched construct;
+ otherwise, the linizer is left in an unknown state.
+
+ A function called is...() keeps the linizer state intact.
+*/
+
+/*
+ Returns true if the current line (and upwards) forms a braceless
+ control statement; otherwise returns false.
+
+ The first line of the following example is a "braceless control
+ statement":
+
+ if (x)
+ y;
+*/
+bool Indenter::matchBracelessControlStatement()
+{
+ int delimDepth = 0;
+
+ const QChar semicolon = QLatin1Char(';');
+
+
+ if (yyLine->endsWith(m_constants.m_else))
+ return true;
+
+ if (!yyLine->endsWith(QLatin1Char(')')))
+ return false;
+
+ for (int i = 0; i < SmallRoof; i++) {
+ int j = yyLine->length();
+ while (j > 0) {
+ j--;
+ QChar ch = (*yyLine)[j];
+
+ switch (ch.unicode()) {
+ case ')':
+ delimDepth++;
+ break;
+ case '(':
+ delimDepth--;
+ if (delimDepth == 0) {
+ if (yyLine->contains(m_constants.m_iflikeKeyword)) {
+ /*
+ We have
+
+ if (x)
+ y
+
+ "if (x)" is not part of the statement
+ "y".
+ */
+ return true;
+ }
+ }
+ if (delimDepth == -1) {
+ /*
+ We have
+
+ if ((1 +
+ 2)
+
+ and not
+
+ if (1 +
+ 2)
+ */
+ return false;
+ }
+ break;
+ case '{':
+ case '}':
+ case ';':
+ /*
+ We met a statement separator, but not where we
+ expected it. What follows is probably a weird
+ continuation line. Be careful with ';' in for,
+ though.
+ */
+ if (ch != semicolon || delimDepth == 0)
+ return false;
+ }
+ }
+
+ if (!readLine())
+ break;
+ }
+ return false;
+}
+
+/*
+ Returns true if yyLine is an unfinished line; otherwise returns
+ false.
+
+ In many places we'll use the terms "standalone line", "unfinished
+ line" and "continuation line". The meaning of these should be
+ evident from this code example:
+
+ a = b; // standalone line
+ c = d + // unfinished line
+ e + // unfinished continuation line
+ f + // unfinished continuation line
+ g; // continuation line
+*/
+bool Indenter::isUnfinishedLine()
+{
+ bool unf = false;
+
+ YY_SAVE();
+
+ const QChar openingParenthesis = QLatin1Char('(');
+ const QChar semicolon = QLatin1Char(';');
+
+ if (yyLine->isEmpty())
+ return false;
+
+ const QChar lastCh = (*yyLine)[ yyLine->length() - 1];
+ if (! m_constants.m_bracesSemicolon.contains(lastCh) && !yyLine->endsWith(m_constants.m_3dots)) {
+ /*
+ It doesn't end with ';' or similar. If it's neither
+ "Q_OBJECT" nor "if (x)" nor is a template function, it must be an unfinished line.
+ */
+ unf = (!yyLine->contains(m_constants.m_qobject) &&
+ !matchBracelessControlStatement() &&
+ !yyLine->contains(m_constants.m_templateFunc));
+ } else if (lastCh == semicolon) {
+ if (lastParen(*yyLine) == openingParenthesis) {
+ /*
+ Exception:
+
+ for (int i = 1; i < 10;
+ */
+ unf = true;
+ } else if (readLine() && yyLine->endsWith(semicolon) &&
+ lastParen(*yyLine) == openingParenthesis) {
+ /*
+ Exception:
+
+ for (int i = 1;
+ i < 10;
+ */
+ unf = true;
+ }
+ }
+
+ YY_RESTORE();
+ return unf;
+}
+
+/*
+ Returns true if yyLine is a continuation line; otherwise returns
+ false.
+*/
+bool Indenter::isContinuationLine()
+{
+ YY_SAVE();
+ const bool cont = readLine() && isUnfinishedLine();
+ YY_RESTORE();
+ return cont;
+}
+
+/*
+ Returns the recommended indent for the bottom line of yyProgram,
+ assuming it's a continuation line.
+
+ We're trying to align the continuation line against some parenthesis
+ or other bracked left opened on a previous line, or some interesting
+ operator such as '='.
+*/
+int Indenter::indentForContinuationLine()
+{
+ int braceDepth = 0;
+ int delimDepth = 0;
+
+ bool leftBraceFollowed = *yyLeftBraceFollows;
+
+ const QChar equals = QLatin1Char('=');
+ const QChar comma = QLatin1Char(',');
+ const QChar openingParenthesis = QLatin1Char('(');
+ const QChar closingParenthesis = QLatin1Char(')');
+
+ for (int i = 0; i < SmallRoof; i++) {
+ int hook = -1;
+
+ int j = yyLine->length();
+ while (j > 0 && hook < 0) {
+ j--;
+ QChar ch = (*yyLine)[j];
+
+ switch (ch.unicode()) {
+ case ')':
+ case ']':
+ delimDepth++;
+ break;
+ case '}':
+ braceDepth++;
+ break;
+ case '(':
+ case '[':
+ delimDepth--;
+ /*
+ An unclosed delimiter is a good place to align at,
+ at least for some styles (including Trolltech's).
+ */
+ if (delimDepth == -1)
+ hook = j;
+ break;
+ case '{':
+ braceDepth--;
+ /*
+ A left brace followed by other stuff on the same
+ line is typically for an enum or an initializer.
+ Such a brace must be treated just like the other
+ delimiters.
+ */
+ if (braceDepth == -1) {
+ if (j < yyLine->length() - 1) {
+ hook = j;
+ } else {
+ return 0; // shouldn't happen
+ }
+ }
+ break;
+ case '=':
+ /*
+ An equal sign is a very natural alignment hook
+ because it's usually the operator with the lowest
+ precedence in statements it appears in. Case in
+ point:
+
+ int x = 1 +
+ 2;
+
+ However, we have to beware of constructs such as
+ default arguments and explicit enum constant
+ values:
+
+ void foo(int x = 0,
+ int y = 0);
+
+ And not
+
+ void foo(int x = 0,
+ int y = 0);
+
+ These constructs are caracterized by a ',' at the
+ end of the unfinished lines or by unbalanced
+ parentheses.
+ */
+ if (j > 0 && j < yyLine->length() - 1
+ && !m_constants.m_operators.contains((*yyLine)[j - 1])
+ && (*yyLine)[j + 1] != equals) {
+ if (braceDepth == 0 && delimDepth == 0 &&
+ !yyLine->endsWith(comma) &&
+ (yyLine->contains(openingParenthesis) == yyLine->contains(closingParenthesis)))
+ hook = j;
+ }
+ }
+ }
+
+ if (hook >= 0) {
+ /*
+ Yes, we have a delimiter or an operator to align
+ against! We don't really align against it, but rather
+ against the following token, if any. In this example,
+ the following token is "11":
+
+ int x = (11 +
+ 2);
+
+ If there is no such token, we use a continuation indent:
+
+ static QRegExp foo(QString(
+ "foo foo foo foo foo foo foo foo foo"));
+ */
+ hook++;
+ while (hook < yyLine->length()) {
+ if (!(*yyLine)[hook].isSpace())
+ return columnForIndex(*yyLine, hook);
+ hook++;
+ }
+ return indentOfLine(*yyLine) + ppContinuationIndentSize;
+ }
+
+ if (braceDepth != 0)
+ break;
+
+ /*
+ The line's delimiters are balanced. It looks like a
+ continuation line or something.
+ */
+ if (delimDepth == 0) {
+ if (leftBraceFollowed) {
+ /*
+ We have
+
+ int main()
+ {
+
+ or
+
+ Bar::Bar()
+ : Foo(x)
+ {
+
+ The "{" should be flush left.
+ */
+ if (!isContinuationLine())
+ return indentOfLine(*yyLine);
+ } else if (isContinuationLine() || yyLine->endsWith(comma)) {
+ /*
+ We have
+
+ x = a +
+ b +
+ c;
+
+ or
+
+ int t[] = {
+ 1, 2, 3,
+ 4, 5, 6
+
+ The "c;" should fall right under the "b +", and the
+ "4, 5, 6" right under the "1, 2, 3,".
+ */
+ return indentOfLine(*yyLine);
+ } else {
+ /*
+ We have
+
+ stream << 1 +
+ 2;
+
+ We could, but we don't, try to analyze which
+ operator has precedence over which and so on, to
+ obtain the excellent result
+
+ stream << 1 +
+ 2;
+
+ We do have a special trick above for the assignment
+ operator above, though.
+ */
+ return indentOfLine(*yyLine) + ppContinuationIndentSize;
+ }
+ }
+
+ if (!readLine())
+ break;
+ }
+ return 0;
+}
+
+/*
+ Returns the recommended indent for the bottom line of yyProgram if
+ that line is standalone (or should be indented likewise).
+
+ Indenting a standalone line is tricky, mostly because of braceless
+ control statements. Grossly, we are looking backwards for a special
+ line, a "hook line", that we can use as a starting point to indent,
+ and then modify the indentation level according to the braces met
+ along the way to that hook.
+
+ Let's consider a few examples. In all cases, we want to indent the
+ bottom line.
+
+ Example 1:
+
+ x = 1;
+ y = 2;
+
+ The hook line is "x = 1;". We met 0 opening braces and 0 closing
+ braces. Therefore, "y = 2;" inherits the indent of "x = 1;".
+
+ Example 2:
+
+ if (x) {
+ y;
+
+ The hook line is "if (x) {". No matter what precedes it, "y;" has
+ to be indented one level deeper than the hook line, since we met one
+ opening brace along the way.
+
+ Example 3:
+
+ if (a)
+ while (b) {
+ c;
+ }
+ d;
+
+ To indent "d;" correctly, we have to go as far as the "if (a)".
+ Compare with
+
+ if (a) {
+ while (b) {
+ c;
+ }
+ d;
+
+ Still, we are striving to go back as little as possible to accommodate
+ people with irregular indentation schemes. A hook line near at hand
+ is much more reliable than a remote one.
+*/
+int Indenter::indentForStandaloneLine()
+{
+ const QChar semicolon = QLatin1Char(';');
+ const QChar openingBrace = QLatin1Char('{');
+
+ for (int i = 0; i < SmallRoof; i++) {
+ if (!*yyLeftBraceFollows) {
+ YY_SAVE();
+
+ if (matchBracelessControlStatement()) {
+ /*
+ The situation is this, and we want to indent "z;":
+
+ if (x &&
+ y)
+ z;
+
+ yyLine is "if (x &&".
+ */
+ return indentOfLine(*yyLine) + ppIndentSize;
+ }
+ YY_RESTORE();
+ }
+
+ if (yyLine->endsWith(semicolon) || yyLine->count(openingBrace) > 0) {
+ /*
+ The situation is possibly this, and we want to indent
+ "z;":
+
+ while (x)
+ y;
+ z;
+
+ We return the indent of "while (x)". In place of "y;",
+ any arbitrarily complex compound statement can appear.
+ */
+
+ if (*yyBraceDepth > 0) {
+ do {
+ if (!readLine())
+ break;
+ } while (*yyBraceDepth > 0);
+ }
+
+ LinizerState hookState;
+
+ while (isContinuationLine())
+ readLine();
+ hookState = *yyLinizerState;
+
+ readLine();
+ if (*yyBraceDepth <= 0) {
+ do {
+ if (!matchBracelessControlStatement())
+ break;
+ hookState = *yyLinizerState;
+ } while (readLine());
+ }
+
+ *yyLinizerState = hookState;
+
+ while (isContinuationLine())
+ readLine();
+
+ /*
+ Never trust lines containing only '{' or '}', as some
+ people (Richard M. Stallman) format them weirdly.
+ */
+ if (yyLine->trimmed().length() > 1) {
+ if (!ppDoubleIndentBlocks)
+ return indentOfLine(*yyLine) - *yyBraceDepth * ppIndentSize;
+ else {
+ if (*yyBraceDepth == -1 && indentOfLine(*yyLine) == 0)
+ return ppIndentSize; // don't do double indent for upper level blocks
+ return indentOfLine(*yyLine) - *yyBraceDepth * ppIndentSize * 2;
+ }
+ }
+ }
+
+ if (!readLine())
+ return -*yyBraceDepth * ppIndentSize;
+ }
+ return 0;
+}
+
+/*
+ Returns the recommended indent for the bottom line of program.
+ Unless null, typedIn stores the character of yyProgram that
+ triggered reindentation.
+
+ This function works better if typedIn is set properly; it is
+ slightly more conservative if typedIn is completely wild, and
+ slighly more liberal if typedIn is always null. The user might be
+ annoyed by the liberal behavior.
+*/
+int Indenter::indentForBottomLine(const Iterator ¤t,
+ const Iterator &programBegin,
+ const Iterator &programEnd,
+ QChar typedIn)
+{
+ if (programBegin == programEnd)
+ return 0;
+
+ yyProgramBegin = programBegin;
+ yyProgramEnd = programEnd;
+
+ startLinizer();
+
+ Iterator lastIt = current;
+
+ QString bottomLine = *lastIt;
+ QChar firstCh = firstNonWhiteSpace(bottomLine);
+ int indent;
+
+ const QChar hash = QLatin1Char('#');
+ const QChar openingBrace = QLatin1Char('{');
+ const QChar closingBrace = QLatin1Char('}');
+ const QChar colon = QLatin1Char(':');
+
+ if (bottomLineStartsInCComment()) {
+ /*
+ The bottom line starts in a C-style comment. Indent it
+ smartly, unless the user has already played around with it,
+ in which case it's better to leave her stuff alone.
+ */
+ if (isOnlyWhiteSpace(bottomLine)) {
+ indent = indentWhenBottomLineStartsInCComment();
+ } else {
+ indent = indentOfLine(bottomLine);
+ }
+ } else if (okay(typedIn, hash) && firstCh == hash) {
+ /*
+ Preprocessor directives go flush left.
+ */
+ indent = 0;
+ } else {
+ if (isUnfinishedLine()) {
+ indent = indentForContinuationLine();
+ } else {
+ indent = indentForStandaloneLine();
+ }
+
+ if (ppIndentBraces && firstCh == openingBrace) {
+ indent += ppIndentSize;
+ } else if (firstCh == closingBrace) {
+ /*
+ A closing brace is one level more to the left than the
+ code it follows.
+ */
+ indent -= ppIndentSize;
+ /*
+ But if braces indenting is enabled the shift exists
+ */
+ if (ppIndentBraces)
+ indent += ppIndentSize;
+ /*
+ Double indenting of code blocks makes block righter, so move our brace back
+ */
+ if (ppDoubleIndentBlocks)
+ indent -= ppIndentSize;
+
+ } else if (okay(typedIn, colon)) {
+ if (m_constants.m_caseLabel.indexIn(bottomLine) != -1) {
+ /*
+ Move a case label (or the ':' in front of a
+ constructor initialization list) one level to the
+ left, but only if the user did not play around with
+ it yet. Some users have exotic tastes in the
+ matter, and most users probably are not patient
+ enough to wait for the final ':' to format their
+ code properly.
+
+ We don't attempt the same for goto labels, as the
+ user is probably the middle of "foo::bar". (Who
+ uses goto, anyway?)
+ */
+ if (indentOfLine(bottomLine) <= indent)
+ indent -= ppIndentSize;
+ else
+ indent = indentOfLine(bottomLine);
+ }
+ }
+ }
+ if (ppIndentBraces && indent == ppIndentSize &&
+ (firstCh == openingBrace || firstCh == closingBrace) ) {
+ indent = 0;
+ }
+ return qMax(0, indent);
+}
+
+} // namespace SharedTools
#ifndef INDENTER_H
#define INDENTER_H
+#include "texteditor/basetexteditor.h"
+#include "texteditor/textblockiterator.h"
+
#include <QtCore/QString>
#include <QtCore/QStringList>
* given as a list of strings, with the bottom line being the line to
* indent. The actual program might contain extra lines, but those are
* uninteresting and not passed over to us. */
-template <class Iterator>
struct LinizerState {
QString line;
int braceDepth;
bool leftBraceFollows;
- Iterator iter;
+ TextEditor::TextBlockIterator iter;
bool inCComment;
bool pendingRightBrace;
};
* of a sequence of code lines represented as QString.
* When setting the parameters, be careful to
* specify the correct template parameters (best use a typedef). */
-template <class Iterator>
class Indenter {
+ typedef TextEditor::TextBlockIterator Iterator;
Indenter(const Indenter&);
Indenter &operator=(const Indenter&);
Indenter();
Iterator yyProgramBegin;
Iterator yyProgramEnd;
- typedef typename IndenterInternal::LinizerState<Iterator> LinizerState;
+ typedef IndenterInternal::LinizerState LinizerState;
LinizerState *yyLinizerState ;
};
}
-#include "indenter_impl.h"
-
#endif // INDENTER_H
INCLUDEPATH *= $$PWD
-SOURCES += $$PWD/constants.cpp
-HEADERS += $$PWD/indenter.h \
- $$PWD/indenter_impl.h
+SOURCES += $$PWD/constants.cpp $$PWD/indenter.cpp
+HEADERS += $$PWD/indenter.h
+++ /dev/null
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** Commercial Usage
-**
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
-**
-** GNU Lesser General Public License Usage
-**
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
-**
-**************************************************************************/
-
-#ifndef INDENTER_C
-#define INDENTER_C
-
-/*
- This file is a self-contained interactive indenter for C++ and Qt
- Script.
-
- The general problem of indenting a C++ program is ill posed. On the
- one hand, an indenter has to analyze programs written in a
- free-form formal language that is best described in terms of
- tokens, not characters, not lines. On the other hand, indentation
- applies to lines and white space characters matter, and otherwise
- the programs to indent are formally invalid in general, as they are
- being edited.
-
- The approach taken here works line by line. We receive a program
- consisting of N lines or more, and we want to compute the
- indentation appropriate for the Nth line. Lines beyond the Nth
- lines are of no concern to us, so for simplicity we pretend the
- program has exactly N lines and we call the Nth line the "bottom
- line". Typically, we have to indent the bottom line when it's still
- empty, so we concentrate our analysis on the N - 1 lines that
- precede.
-
- By inspecting the (N - 1)-th line, the (N - 2)-th line, ...
- backwards, we determine the kind of the bottom line and indent it
- accordingly.
-
- * The bottom line is a comment line. See
- bottomLineStartsInCComment() and
- indentWhenBottomLineStartsInCComment().
- * The bottom line is a continuation line. See isContinuationLine()
- and indentForContinuationLine().
- * The bottom line is a standalone line. See
- indentForStandaloneLine().
-
- Certain tokens that influence the indentation, notably braces, are
- looked for in the lines. This is done by simple string comparison,
- without a real tokenizer. Confusing constructs such as comments and
- string literals are removed beforehand.
-*/
-
-namespace SharedTools {
-
-/* qmake ignore Q_OBJECT */
-
-/*
- The indenter avoids getting stuck in almost infinite loops by
- imposing arbitrary limits on the number of lines it analyzes when
- looking for a construct.
-
- For example, the indenter never considers more than BigRoof lines
- backwards when looking for the start of a C-style comment.
-*/
-namespace {
- enum { SmallRoof = 40, BigRoof = 400 };
-
-/*
- The indenter supports a few parameters:
-
- * ppHardwareTabSize is the size of a '\t' in your favorite editor.
- * ppIndentSize is the size of an indentation, or software tab
- size.
- * ppContinuationIndentSize is the extra indent for a continuation
- line, when there is nothing to align against on the previous
- line.
- * ppCommentOffset is the indentation within a C-style comment,
- when it cannot be picked up.
- * ppIndentBraces will indent braces flush with an indented code
- block.
- * ppDoubleIndentBlocks do double indent of blocks so as together
- with ppIndentBraces enabled it form some sort of GNU indenting style
-*/
-
-
- enum { ppCommentOffset = 1 };
-}
-
-template <class Iterator>
-Indenter<Iterator>::Indenter() :
- ppHardwareTabSize(8),
- ppIndentSize(4),
- ppIndentBraces(false),
- ppContinuationIndentSize(8),
- ppDoubleIndentBlocks(false),
- yyLinizerState(new LinizerState),
- yyLine(0),
- yyBraceDepth(0),
- yyLeftBraceFollows(0)
-{
-}
-
-template <class Iterator>
-Indenter<Iterator>::~Indenter()
-{
- delete yyLinizerState;
-}
-
-template <class Iterator>
-Indenter<Iterator> &Indenter<Iterator>::instance()
-{
- static Indenter rc;
- return rc;
-}
-
-template <class Iterator>
-void Indenter<Iterator>::setIndentSize(int size)
-{
- ppIndentSize = size;
- ppContinuationIndentSize = 2 * size;
-}
-
-template <class Iterator>
-void Indenter<Iterator>::setTabSize(int size )
-{
- ppHardwareTabSize = size;
-}
-
-template <class Iterator>
-void Indenter<Iterator>::setIndentBraces(bool indent)
-{
- ppIndentBraces = indent;
-}
-
-template <class Iterator>
-void Indenter<Iterator>::setDoubleIndentBlocks(bool indent)
-{
- ppDoubleIndentBlocks = indent;
-}
-
-/*
- Returns the first non-space character in the string t, or
- QChar::null if the string is made only of white space.
-*/
-template <class Iterator>
-QChar Indenter<Iterator>::firstNonWhiteSpace( const QString& t )
-{
- if (const int len = t.length())
- for ( int i = 0; i < len; i++)
- if ( !t[i].isSpace() )
- return t[i];
- return QChar::Null;
-}
-
-/*
- Returns true if string t is made only of white space; otherwise
- returns false.
-*/
-template <class Iterator>
-bool Indenter<Iterator>::isOnlyWhiteSpace( const QString& t )
-{
- return t.isEmpty() || firstNonWhiteSpace( t ).isNull();
-}
-
-/*
- Assuming string t is a line, returns the column number of a given
- index. Column numbers and index are identical for strings that don't
- contain '\t's.
-*/
-template <class Iterator>
-int Indenter<Iterator>::columnForIndex( const QString& t, int index ) const
-{
- int col = 0;
- if ( index > t.length() )
- index = t.length();
-
- const QChar tab = QLatin1Char('\t');
-
- for ( int i = 0; i < index; i++ ) {
- if ( t[i] == tab ) {
- col = ( (col / ppHardwareTabSize) + 1 ) * ppHardwareTabSize;
- } else {
- col++;
- }
- }
- return col;
-}
-
-/*
- Returns the indentation size of string t.
-*/
-template <class Iterator>
-int Indenter<Iterator>::indentOfLine( const QString& t ) const
-{
- return columnForIndex( t, t.indexOf(firstNonWhiteSpace(t)) );
-}
-
-/*
- Replaces t[k] by ch, unless t[k] is '\t'. Tab characters are better
- left alone since they break the "index equals column" rule. No
- provisions are taken against '\n' or '\r', which shouldn't occur in
- t anyway.
-*/
-static inline void eraseChar( QString& t, int k, QChar ch )
-{
- if ( t[k] != QLatin1Char('\t') )
- t[k] = ch;
-}
-
-/*
- Removes some nefast constructs from a code line and returns the
- resulting line.
-*/
-template <class Iterator>
-QString Indenter<Iterator>::trimmedCodeLine( const QString& t )
-{
- QString trimmed = t;
- int k;
-
- const QChar capitalX = QLatin1Char('X');
- const QChar blank = QLatin1Char(' ');
- const QChar colon = QLatin1Char(':');
- const QChar semicolon = QLatin1Char(';');
- /*
- Replace character and string literals by X's, since they may
- contain confusing characters (such as '{' and ';'). "Hello!" is
- replaced by XXXXXXXX. The literals are rigourously of the same
- length before and after; otherwise, we would break alignment of
- continuation lines.
- */
- k = 0;
- while ( (k = m_constants.m_literal.indexIn(trimmed), k) != -1 ) {
- const int matchedLength = m_constants.m_literal.matchedLength();
- for ( int i = 0; i < matchedLength ; i++ )
- eraseChar( trimmed, k + i, capitalX );
- k += matchedLength;
- }
-
- /*
- Replace inline C-style comments by spaces. Other comments are
- handled elsewhere.
- */
- k = 0;
- while ( (k = m_constants.m_inlineCComment.indexIn(trimmed, k)) != -1 ) {
- const int matchedLength = m_constants.m_inlineCComment.matchedLength();
- for ( int i = 0; i < matchedLength; i++ )
- eraseChar( trimmed, k + i, blank );
- k += matchedLength;
- }
-
- /*
- Replace goto and switch labels by whitespace, but be careful
- with this case:
-
- foo1: bar1;
- bar2;
- */
- while ( trimmed.lastIndexOf(colon ) != -1 && m_constants.m_label.indexIn(trimmed) != -1 ) {
- const QString cap1 = m_constants.m_label.cap( 1 );
- const int pos1 = m_constants.m_label.pos( 1 );
- int stop = cap1.length();
-
- if ( pos1 + stop < trimmed.length() && ppIndentSize < stop )
- stop = ppIndentSize;
-
- int i = 0;
- while ( i < stop ) {
- eraseChar( trimmed, pos1 + i, blank );
- i++;
- }
- while ( i < cap1.length() ) {
- eraseChar( trimmed, pos1 + i,semicolon );
- i++;
- }
- }
-
- /*
- Remove C++-style comments.
- */
- k = trimmed.indexOf(m_constants.m_slashSlash );
- if ( k != -1 )
- trimmed.truncate( k );
-
- return trimmed;
-}
-
-/*
- Returns '(' if the last parenthesis is opening, ')' if it is
- closing, and QChar::null if there are no parentheses in t.
-*/
-static inline QChar lastParen( const QString& t )
-{
-
- const QChar opening = QLatin1Char('(');
- const QChar closing = QLatin1Char(')');
-
-
- int i = t.length();
- while ( i > 0 ) {
- i--;
- const QChar c = t[i];
- if (c == opening || c == closing )
- return c;
- }
- return QChar::Null;
-}
-
-/*
- Returns true if typedIn the same as okayCh or is null; otherwise
- returns false.
-*/
-static inline bool okay( QChar typedIn, QChar okayCh )
-{
- return typedIn == QChar::Null || typedIn == okayCh;
-}
-
-
-/*
- Saves and restores the state of the global linizer. This enables
- backtracking.
-*/
-#define YY_SAVE() \
- LinizerState savedState = *yyLinizerState
-#define YY_RESTORE() \
- *yyLinizerState = savedState
-
-/*
- Advances to the previous line in yyProgram and update yyLine
- accordingly. yyLine is cleaned from comments and other damageable
- constructs. Empty lines are skipped.
-*/
-template <class Iterator>
-bool Indenter<Iterator>::readLine()
-{
- int k;
-
- const QChar openingBrace = QLatin1Char('{');
- const QChar closingBrace = QLatin1Char('}');
- const QChar blank = QLatin1Char(' ');
- const QChar hash = QLatin1Char('#');
-
- yyLinizerState->leftBraceFollows =
- ( firstNonWhiteSpace(yyLinizerState->line) == openingBrace );
-
- do {
- if ( yyLinizerState->iter == yyProgramBegin ) {
- yyLinizerState->line = QString::null;
- return false;
- }
-
- --yyLinizerState->iter;
- yyLinizerState->line = *yyLinizerState->iter;
-
- yyLinizerState->line = trimmedCodeLine( yyLinizerState->line );
-
- /*
- Remove C-style comments that span multiple lines. If the
- bottom line starts in a C-style comment, we are not aware
- of that and eventually yyLine will contain a slash-aster.
-
- Notice that both if's can be executed, since
- yyLinizerState->inCComment is potentially set to false in
- the first if. The order of the if's is also important.
- */
-
- if ( yyLinizerState->inCComment ) {
-
- k = yyLinizerState->line.indexOf( m_constants.m_slashAster );
- if ( k == -1 ) {
- yyLinizerState->line = QString::null;
- } else {
- yyLinizerState->line.truncate( k );
- yyLinizerState->inCComment = false;
- }
- }
-
- if ( !yyLinizerState->inCComment ) {
- k = yyLinizerState->line.indexOf( m_constants.m_asterSlash );
- if ( k != -1 ) {
- for ( int i = 0; i < k + 2; i++ )
- eraseChar( yyLinizerState->line, i, blank );
- yyLinizerState->inCComment = true;
- }
- }
-
- /*
- Remove preprocessor directives.
- */
- k = 0;
- while ( k < yyLinizerState->line.length() ) {
- QChar ch = yyLinizerState->line[k];
- if ( ch == hash ) {
- yyLinizerState->line = QString::null;
- } else if ( !ch.isSpace() ) {
- break;
- }
- k++;
- }
-
- /*
- Remove trailing spaces.
- */
- k = yyLinizerState->line.length();
- while ( k > 0 && yyLinizerState->line[k - 1].isSpace() )
- k--;
- yyLinizerState->line.truncate( k );
-
- /*
- '}' increment the brace depth and '{' decrements it and not
- the other way around, as we are parsing backwards.
- */
- yyLinizerState->braceDepth +=
- yyLinizerState->line.count( closingBrace ) - yyLinizerState->line.count( openingBrace );
-
- /*
- We use a dirty trick for
-
- } else ...
-
- We don't count the '}' yet, so that it's more or less
- equivalent to the friendly construct
-
- }
- else ...
- */
- if ( yyLinizerState->pendingRightBrace )
- yyLinizerState->braceDepth++;
- yyLinizerState->pendingRightBrace =
- ( m_constants.m_braceX.indexIn(yyLinizerState->line) == 0 );
- if ( yyLinizerState->pendingRightBrace )
- yyLinizerState->braceDepth--;
- } while ( yyLinizerState->line.isEmpty() );
-
- return true;
-}
-
-/*
- Resets the linizer to its initial state, with yyLine containing the
- line above the bottom line of the program.
-*/
-template <class Iterator>
-void Indenter<Iterator>::startLinizer()
-{
- yyLinizerState->braceDepth = 0;
- yyLinizerState->inCComment = false;
- yyLinizerState->pendingRightBrace = false;
-
- yyLine = &yyLinizerState->line;
- yyBraceDepth = &yyLinizerState->braceDepth;
- yyLeftBraceFollows = &yyLinizerState->leftBraceFollows;
-
- yyLinizerState->iter = yyProgramEnd;
- --yyLinizerState->iter;
- yyLinizerState->line = *yyLinizerState->iter;
- readLine();
-}
-
-/*
- Returns true if the start of the bottom line of yyProgram (and
- potentially the whole line) is part of a C-style comment; otherwise
- returns false.
-*/
-template <class Iterator>
-bool Indenter<Iterator>::bottomLineStartsInCComment()
-{
- /*
- We could use the linizer here, but that would slow us down
- terribly. We are better to trim only the code lines we need.
- */
- Iterator p = yyProgramEnd;
- --p; // skip bottom line
-
- for ( int i = 0; i < BigRoof; i++ ) {
- if ( p == yyProgramBegin )
- return false;
- --p;
-
- if ( (*p).contains(m_constants.m_slashAster) || (*p).contains(m_constants.m_asterSlash) ) {
- QString trimmed = trimmedCodeLine( *p );
-
- if ( trimmed.contains(m_constants.m_slashAster) ) {
- return true;
- } else if ( trimmed.contains(m_constants.m_asterSlash) ) {
- return false;
- }
- }
- }
- return false;
-}
-
-/*
- Returns the recommended indent for the bottom line of yyProgram
- assuming that it starts in a C-style comment, a condition that is
- tested elsewhere.
-
- Essentially, we're trying to align against some text on the previous
- line.
-*/
-template <class Iterator>
-int Indenter<Iterator>::indentWhenBottomLineStartsInCComment() const
-{
- int k = yyLine->lastIndexOf(m_constants.m_slashAster );
- if ( k == -1 ) {
- /*
- We found a normal text line in a comment. Align the
- bottom line with the text on this line.
- */
- return indentOfLine( *yyLine );
- } else {
- /*
- The C-style comment starts on this line. If there is
- text on the same line, align with it. Otherwise, align
- with the slash-aster plus a given offset.
- */
- const int indent = columnForIndex( *yyLine, k );
- k += 2;
- while ( k < yyLine->length() ) {
- if ( !(*yyLine)[k].isSpace() )
- return columnForIndex( *yyLine, k );
- k++;
- }
- return indent + ppCommentOffset;
- }
-}
-
-/*
- A function called match...() modifies the linizer state. If it
- returns true, yyLine is the top line of the matched construct;
- otherwise, the linizer is left in an unknown state.
-
- A function called is...() keeps the linizer state intact.
-*/
-
-/*
- Returns true if the current line (and upwards) forms a braceless
- control statement; otherwise returns false.
-
- The first line of the following example is a "braceless control
- statement":
-
- if ( x )
- y;
-*/
-template <class Iterator>
-bool Indenter<Iterator>::matchBracelessControlStatement()
-{
- int delimDepth = 0;
-
- const QChar semicolon = QLatin1Char(';');
-
-
- if ( yyLine->endsWith(m_constants.m_else))
- return true;
-
- if ( !yyLine->endsWith(QLatin1Char(')')))
- return false;
-
- for ( int i = 0; i < SmallRoof; i++ ) {
- int j = yyLine->length();
- while ( j > 0 ) {
- j--;
- QChar ch = (*yyLine)[j];
-
- switch ( ch.unicode() ) {
- case ')':
- delimDepth++;
- break;
- case '(':
- delimDepth--;
- if ( delimDepth == 0 ) {
- if ( yyLine->contains(m_constants.m_iflikeKeyword) ) {
- /*
- We have
-
- if ( x )
- y
-
- "if ( x )" is not part of the statement
- "y".
- */
- return true;
- }
- }
- if ( delimDepth == -1 ) {
- /*
- We have
-
- if ( (1 +
- 2)
-
- and not
-
- if ( 1 +
- 2 )
- */
- return false;
- }
- break;
- case '{':
- case '}':
- case ';':
- /*
- We met a statement separator, but not where we
- expected it. What follows is probably a weird
- continuation line. Be careful with ';' in for,
- though.
- */
- if ( ch != semicolon || delimDepth == 0 )
- return false;
- }
- }
-
- if ( !readLine() )
- break;
- }
- return false;
-}
-
-/*
- Returns true if yyLine is an unfinished line; otherwise returns
- false.
-
- In many places we'll use the terms "standalone line", "unfinished
- line" and "continuation line". The meaning of these should be
- evident from this code example:
-
- a = b; // standalone line
- c = d + // unfinished line
- e + // unfinished continuation line
- f + // unfinished continuation line
- g; // continuation line
-*/
-template <class Iterator>
-bool Indenter<Iterator>::isUnfinishedLine()
-{
- bool unf = false;
-
- YY_SAVE();
-
- const QChar openingParenthesis = QLatin1Char('(');
- const QChar semicolon = QLatin1Char(';');
-
- if ( yyLine->isEmpty() )
- return false;
-
- const QChar lastCh = (*yyLine)[ yyLine->length() - 1];
- if ( ! m_constants.m_bracesSemicolon.contains(lastCh) && !yyLine->endsWith(m_constants.m_3dots) ) {
- /*
- It doesn't end with ';' or similar. If it's neither
- "Q_OBJECT" nor "if ( x )" nor is a template function, it must be an unfinished line.
- */
- unf = ( !yyLine->contains(m_constants.m_qobject) &&
- !matchBracelessControlStatement() &&
- !yyLine->contains(m_constants.m_templateFunc) );
- } else if ( lastCh == semicolon ) {
- if ( lastParen(*yyLine) == openingParenthesis ) {
- /*
- Exception:
-
- for ( int i = 1; i < 10;
- */
- unf = true;
- } else if ( readLine() && yyLine->endsWith(semicolon) &&
- lastParen(*yyLine) == openingParenthesis ) {
- /*
- Exception:
-
- for ( int i = 1;
- i < 10;
- */
- unf = true;
- }
- }
-
- YY_RESTORE();
- return unf;
-}
-
-/*
- Returns true if yyLine is a continuation line; otherwise returns
- false.
-*/
-template <class Iterator>
-bool Indenter<Iterator>::isContinuationLine()
-{
- YY_SAVE();
- const bool cont = readLine() && isUnfinishedLine();
- YY_RESTORE();
- return cont;
-}
-
-/*
- Returns the recommended indent for the bottom line of yyProgram,
- assuming it's a continuation line.
-
- We're trying to align the continuation line against some parenthesis
- or other bracked left opened on a previous line, or some interesting
- operator such as '='.
-*/
-template <class Iterator>
-int Indenter<Iterator>::indentForContinuationLine()
-{
- int braceDepth = 0;
- int delimDepth = 0;
-
- bool leftBraceFollowed = *yyLeftBraceFollows;
-
- const QChar equals = QLatin1Char('=');
- const QChar comma = QLatin1Char(',');
- const QChar openingParenthesis = QLatin1Char('(');
- const QChar closingParenthesis = QLatin1Char(')');
-
- for ( int i = 0; i < SmallRoof; i++ ) {
- int hook = -1;
-
- int j = yyLine->length();
- while ( j > 0 && hook < 0 ) {
- j--;
- QChar ch = (*yyLine)[j];
-
- switch ( ch.unicode() ) {
- case ')':
- case ']':
- delimDepth++;
- break;
- case '}':
- braceDepth++;
- break;
- case '(':
- case '[':
- delimDepth--;
- /*
- An unclosed delimiter is a good place to align at,
- at least for some styles (including Trolltech's).
- */
- if ( delimDepth == -1 )
- hook = j;
- break;
- case '{':
- braceDepth--;
- /*
- A left brace followed by other stuff on the same
- line is typically for an enum or an initializer.
- Such a brace must be treated just like the other
- delimiters.
- */
- if ( braceDepth == -1 ) {
- if ( j < yyLine->length() - 1 ) {
- hook = j;
- } else {
- return 0; // shouldn't happen
- }
- }
- break;
- case '=':
- /*
- An equal sign is a very natural alignment hook
- because it's usually the operator with the lowest
- precedence in statements it appears in. Case in
- point:
-
- int x = 1 +
- 2;
-
- However, we have to beware of constructs such as
- default arguments and explicit enum constant
- values:
-
- void foo( int x = 0,
- int y = 0 );
-
- And not
-
- void foo( int x = 0,
- int y = 0 );
-
- These constructs are caracterized by a ',' at the
- end of the unfinished lines or by unbalanced
- parentheses.
- */
- if ( j > 0 && j < yyLine->length() - 1
- && !m_constants.m_operators.contains((*yyLine)[j - 1])
- && (*yyLine)[j + 1] != equals ) {
- if ( braceDepth == 0 && delimDepth == 0 &&
- !yyLine->endsWith(comma) &&
- (yyLine->contains(openingParenthesis) == yyLine->contains(closingParenthesis)) )
- hook = j;
- }
- }
- }
-
- if ( hook >= 0 ) {
- /*
- Yes, we have a delimiter or an operator to align
- against! We don't really align against it, but rather
- against the following token, if any. In this example,
- the following token is "11":
-
- int x = ( 11 +
- 2 );
-
- If there is no such token, we use a continuation indent:
-
- static QRegExp foo( QString(
- "foo foo foo foo foo foo foo foo foo") );
- */
- hook++;
- while ( hook < yyLine->length() ) {
- if ( !(*yyLine)[hook].isSpace() )
- return columnForIndex( *yyLine, hook );
- hook++;
- }
- return indentOfLine( *yyLine ) + ppContinuationIndentSize;
- }
-
- if ( braceDepth != 0 )
- break;
-
- /*
- The line's delimiters are balanced. It looks like a
- continuation line or something.
- */
- if ( delimDepth == 0 ) {
- if ( leftBraceFollowed ) {
- /*
- We have
-
- int main()
- {
-
- or
-
- Bar::Bar()
- : Foo( x )
- {
-
- The "{" should be flush left.
- */
- if ( !isContinuationLine() )
- return indentOfLine( *yyLine );
- } else if ( isContinuationLine() || yyLine->endsWith(comma)) {
- /*
- We have
-
- x = a +
- b +
- c;
-
- or
-
- int t[] = {
- 1, 2, 3,
- 4, 5, 6
-
- The "c;" should fall right under the "b +", and the
- "4, 5, 6" right under the "1, 2, 3,".
- */
- return indentOfLine( *yyLine );
- } else {
- /*
- We have
-
- stream << 1 +
- 2;
-
- We could, but we don't, try to analyze which
- operator has precedence over which and so on, to
- obtain the excellent result
-
- stream << 1 +
- 2;
-
- We do have a special trick above for the assignment
- operator above, though.
- */
- return indentOfLine( *yyLine ) + ppContinuationIndentSize;
- }
- }
-
- if ( !readLine() )
- break;
- }
- return 0;
-}
-
-/*
- Returns the recommended indent for the bottom line of yyProgram if
- that line is standalone (or should be indented likewise).
-
- Indenting a standalone line is tricky, mostly because of braceless
- control statements. Grossly, we are looking backwards for a special
- line, a "hook line", that we can use as a starting point to indent,
- and then modify the indentation level according to the braces met
- along the way to that hook.
-
- Let's consider a few examples. In all cases, we want to indent the
- bottom line.
-
- Example 1:
-
- x = 1;
- y = 2;
-
- The hook line is "x = 1;". We met 0 opening braces and 0 closing
- braces. Therefore, "y = 2;" inherits the indent of "x = 1;".
-
- Example 2:
-
- if ( x ) {
- y;
-
- The hook line is "if ( x ) {". No matter what precedes it, "y;" has
- to be indented one level deeper than the hook line, since we met one
- opening brace along the way.
-
- Example 3:
-
- if ( a )
- while ( b ) {
- c;
- }
- d;
-
- To indent "d;" correctly, we have to go as far as the "if ( a )".
- Compare with
-
- if ( a ) {
- while ( b ) {
- c;
- }
- d;
-
- Still, we are striving to go back as little as possible to accommodate
- people with irregular indentation schemes. A hook line near at hand
- is much more reliable than a remote one.
-*/
-template <class Iterator>
-int Indenter<Iterator>::indentForStandaloneLine()
-{
- const QChar semicolon = QLatin1Char(';');
- const QChar openingBrace = QLatin1Char('{');
-
- for ( int i = 0; i < SmallRoof; i++ ) {
- if ( !*yyLeftBraceFollows ) {
- YY_SAVE();
-
- if ( matchBracelessControlStatement() ) {
- /*
- The situation is this, and we want to indent "z;":
-
- if ( x &&
- y )
- z;
-
- yyLine is "if ( x &&".
- */
- return indentOfLine( *yyLine ) + ppIndentSize;
- }
- YY_RESTORE();
- }
-
- if ( yyLine->endsWith(semicolon) || yyLine->count(openingBrace) > 0 ) {
- /*
- The situation is possibly this, and we want to indent
- "z;":
-
- while ( x )
- y;
- z;
-
- We return the indent of "while ( x )". In place of "y;",
- any arbitrarily complex compound statement can appear.
- */
-
- if ( *yyBraceDepth > 0 ) {
- do {
- if ( !readLine() )
- break;
- } while ( *yyBraceDepth > 0 );
- }
-
- LinizerState hookState;
-
- while ( isContinuationLine() )
- readLine();
- hookState = *yyLinizerState;
-
- readLine();
- if ( *yyBraceDepth <= 0 ) {
- do {
- if ( !matchBracelessControlStatement() )
- break;
- hookState = *yyLinizerState;
- } while ( readLine() );
- }
-
- *yyLinizerState = hookState;
-
- while ( isContinuationLine() )
- readLine();
-
- /*
- Never trust lines containing only '{' or '}', as some
- people (Richard M. Stallman) format them weirdly.
- */
- if ( yyLine->trimmed().length() > 1 ) {
- if (!ppDoubleIndentBlocks)
- return indentOfLine( *yyLine ) - *yyBraceDepth * ppIndentSize;
- else {
- if (*yyBraceDepth == -1 && indentOfLine( *yyLine ) == 0)
- return ppIndentSize; // don't do double indent for upper level blocks
- return indentOfLine( *yyLine ) - *yyBraceDepth * ppIndentSize * 2;
- }
- }
- }
-
- if ( !readLine() )
- return -*yyBraceDepth * ppIndentSize;
- }
- return 0;
-}
-
-/*
- Returns the recommended indent for the bottom line of program.
- Unless null, typedIn stores the character of yyProgram that
- triggered reindentation.
-
- This function works better if typedIn is set properly; it is
- slightly more conservative if typedIn is completely wild, and
- slighly more liberal if typedIn is always null. The user might be
- annoyed by the liberal behavior.
-*/
-template <class Iterator>
-int Indenter<Iterator>::indentForBottomLine(const Iterator ¤t,
- const Iterator &programBegin,
- const Iterator &programEnd,
- QChar typedIn )
-{
- if ( programBegin == programEnd )
- return 0;
-
- yyProgramBegin = programBegin;
- yyProgramEnd = programEnd;
-
- startLinizer();
-
- Iterator lastIt = current;
-
- QString bottomLine = *lastIt;
- QChar firstCh = firstNonWhiteSpace( bottomLine );
- int indent;
-
- const QChar hash = QLatin1Char('#');
- const QChar openingBrace = QLatin1Char('{');
- const QChar closingBrace = QLatin1Char('}');
- const QChar colon = QLatin1Char(':');
-
- if ( bottomLineStartsInCComment() ) {
- /*
- The bottom line starts in a C-style comment. Indent it
- smartly, unless the user has already played around with it,
- in which case it's better to leave her stuff alone.
- */
- if ( isOnlyWhiteSpace(bottomLine) ) {
- indent = indentWhenBottomLineStartsInCComment();
- } else {
- indent = indentOfLine( bottomLine );
- }
- } else if ( okay(typedIn, hash) && firstCh == hash ) {
- /*
- Preprocessor directives go flush left.
- */
- indent = 0;
- } else {
- if ( isUnfinishedLine() ) {
- indent = indentForContinuationLine();
- } else {
- indent = indentForStandaloneLine();
- }
-
- if ( ppIndentBraces && firstCh == openingBrace ) {
- indent += ppIndentSize;
- } else if ( firstCh == closingBrace ) {
- /*
- A closing brace is one level more to the left than the
- code it follows.
- */
- indent -= ppIndentSize;
- /*
- But if braces indenting is enabled the shift exists
- */
- if (ppIndentBraces)
- indent += ppIndentSize;
- /*
- Double indenting of code blocks makes block righter, so move our brace back
- */
- if (ppDoubleIndentBlocks)
- indent -= ppIndentSize;
-
- } else if ( okay(typedIn, colon) ) {
- if ( m_constants.m_caseLabel.indexIn(bottomLine) != -1 ) {
- /*
- Move a case label (or the ':' in front of a
- constructor initialization list) one level to the
- left, but only if the user did not play around with
- it yet. Some users have exotic tastes in the
- matter, and most users probably are not patient
- enough to wait for the final ':' to format their
- code properly.
-
- We don't attempt the same for goto labels, as the
- user is probably the middle of "foo::bar". (Who
- uses goto, anyway?)
- */
- if ( indentOfLine(bottomLine) <= indent )
- indent -= ppIndentSize;
- else
- indent = indentOfLine( bottomLine );
- }
- }
- }
- if ( ppIndentBraces && indent == ppIndentSize &&
- (firstCh == openingBrace || firstCh == closingBrace ) ) {
- indent = 0;
- }
- return qMax( 0, indent );
-}
-
-} // namespace SharedTools
-
-#undef YY_SAVE
-#undef YY_RESTORE
-
-#endif // INDENTER_C
#define QT_PCLOSE pclose
#endif
+// Be fast even for debug builds
+#ifdef __GNUC__
+# define ALWAYS_INLINE inline __attribute__((always_inline))
+#elif defined(_MSC_VER)
+# define ALWAYS_INLINE __forceinline
+#else
+# define ALWAYS_INLINE inline
+#endif
+
using namespace ProFileEvaluatorInternal;
QT_BEGIN_NAMESPACE
-static void refFunctions(QHash<QString, ProBlock *> *defs)
-{
- foreach (ProBlock *itm, *defs)
- itm->ref();
-}
-
-static void clearFunctions(QHash<QString, ProBlock *> *defs)
-{
- foreach (ProBlock *itm, *defs)
- itm->deref();
- defs->clear();
-}
-
-static void clearFunctions(ProFileEvaluator::FunctionDefs *defs)
-{
- clearFunctions(&defs->replaceFunctions);
- clearFunctions(&defs->testFunctions);
-}
+using namespace ProStringConstants;
///////////////////////////////////////////////////////////////////////
ProFileOption::~ProFileOption()
{
- clearFunctions(&base_functions);
}
///////////////////////////////////////////////////////////////////////
/////////////// Reading pro file
- struct BlockCursor {
- BlockCursor() : cursor(0) {}
- BlockCursor(ProBlock *blk) : block(blk), cursor(blk->itemsRef()) {}
- ~BlockCursor() { if (cursor) *cursor = 0; }
- void set(ProBlock *blk) { if (cursor) *cursor = 0; block = blk; cursor = blk->itemsRef(); }
- void reset() { if (cursor) { *cursor = 0; cursor = 0; } }
- void append(ProItem *item) { *cursor = item; cursor = item->nextRef(); }
- bool isValid() const { return cursor != 0; }
- ProBlock *block;
- ProItem **cursor;
+ struct BlockScope {
+ BlockScope() : start(0), braceLevel(0), special(false), inBranch(false) {}
+ BlockScope(BlockScope &other) :
+ start(other.start), braceLevel(other.braceLevel),
+ special(other.special), inBranch(other.inBranch) {}
+ ushort *start; // Where this block started; store length here
+ int braceLevel; // Nesting of braces in scope
+ bool special; // Single-line conditionals cannot have else branches
+ bool inBranch; // The 'else' branch of the previous TokBranch is still open
};
- bool read(ProFile *pro);
- bool read(ProFile *pro, const QString &content);
- bool read(ProBlock *pro, const QString &content);
- bool readInternal(ProBlock *pro, const QString &content, ushort *buf);
+ enum ScopeState {
+ StNew, // Fresh scope
+ StCtrl, // Control statement (for or else) met on current line
+ StCond // Conditionals met on current line
+ };
- BlockCursor ¤tBlock();
- void updateItem(ushort *uc, ushort *ptr);
- ProVariable *startVariable(ushort *uc, ushort *ptr);
- void finalizeVariable(ProVariable *var, ushort *uc, ushort *ptr);
- void insertOperator(const char op);
- void enterScope(bool multiLine);
- void leaveScope();
- void finalizeBlock();
+ enum Context { CtxTest, CtxValue, CtxArgs };
+ struct ParseCtx {
+ int parens; // Nesting of non-functional parentheses
+ int argc; // Number of arguments in current function call
+ int litCount; // Number of literals in current expression
+ int expCount; // Number of expansions in current expression
+ Context context;
+ ushort quote; // Enclosing quote type
+ ushort terminator; // '}' if replace function call is braced, ':' if test function
+ };
- QStack<BlockCursor> m_blockstack;
- BlockCursor m_block;
+ bool read(ProFile *pro);
+ bool read(ProFile *pro, const QString &content);
+ bool read(QString *out, const QString &content);
+ bool readInternal(QString *out, const QString &content);
+
+ ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok);
+ ALWAYS_INLINE void putBlockLen(ushort *&tokPtr, uint len);
+ ALWAYS_INLINE void putBlock(ushort *&tokPtr, const ushort *buf, uint len);
+ void putHashStr(ushort *&pTokPtr, const ushort *buf, uint len);
+ void finalizeHashStr(ushort *buf, uint len);
+ void putLineMarker(ushort *&tokPtr);
+ void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr);
+ void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc);
+ void finalizeTest(ushort *&tokPtr);
+ void enterScope(ushort *&tokPtr, bool special, ScopeState state);
+ void leaveScope(ushort *&tokPtr);
+ void flushCond(ushort *&tokPtr);
+ void flushScopes(ushort *&tokPtr);
+
+ QStack<BlockScope> m_blockstack;
+ ScopeState m_state;
+ int m_markLine; // Put marker for this line
+ bool m_canElse; // Conditionals met on previous line, but no scope was opened
+ bool m_invert; // Pending conditional is negated
+ enum { NoOperator, AndOperator, OrOperator } m_operator; // Pending conditional is ORed/ANDed
/////////////// Evaluating pro file contents
- ProItem::ProItemReturn visitProFile(ProFile *pro);
- ProItem::ProItemReturn visitProBlock(ProBlock *block);
- ProItem::ProItemReturn visitProItem(ProItem *item);
- ProItem::ProItemReturn visitProLoopIteration();
- void visitProLoopCleanup();
- void visitProVariable(ProVariable *variable);
- ProItem::ProItemReturn visitProFunction(ProFunction *function);
- void visitProOperator(ProOperator *oper);
- void visitProCondition(ProCondition *condition);
-
- static inline QString map(const QString &var);
- QHash<QString, QStringList> *findValues(const QString &variableName,
- QHash<QString, QStringList>::Iterator *it);
- QStringList &valuesRef(const QString &variableName);
- QStringList valuesDirect(const QString &variableName) const;
- QStringList values(const QString &variableName) const;
+ enum VisitReturn {
+ ReturnFalse,
+ ReturnTrue,
+ ReturnBreak,
+ ReturnNext,
+ ReturnReturn
+ };
+
+ static ALWAYS_INLINE uint getBlockLen(const ushort *&tokPtr);
+ ProString getStr(const ushort *&tokPtr);
+ ProString getHashStr(const ushort *&tokPtr);
+ void evaluateExpression(const ushort *&tokPtr, ProStringList *ret, bool joined);
+ static ALWAYS_INLINE void skipStr(const ushort *&tokPtr);
+ static ALWAYS_INLINE void skipHashStr(const ushort *&tokPtr);
+ void skipExpression(const ushort *&tokPtr);
+
+ VisitReturn visitProFile(ProFile *pro);
+ VisitReturn visitProBlock(const ushort *tokPtr);
+ VisitReturn visitProLoop(const ProString &variable, const ushort *exprPtr,
+ const ushort *tokPtr);
+ void visitProFunctionDef(ushort tok, const ProString &name, const ushort *tokPtr);
+ void visitProVariable(ushort tok, const ProStringList &curr, const ushort *&tokPtr);
+
+ static inline ProString map(const ProString &var);
+ QHash<ProString, ProStringList> *findValues(const ProString &variableName,
+ QHash<ProString, ProStringList>::Iterator *it);
+ ProStringList &valuesRef(const ProString &variableName);
+ ProStringList valuesDirect(const ProString &variableName) const;
+ ProStringList values(const ProString &variableName) const;
QString propertyValue(const QString &val, bool complain = true) const;
- static QStringList split_value_list(const QString &vals);
+ static ProStringList split_value_list(const QString &vals);
bool isActiveConfig(const QString &config, bool regex = false);
- QStringList expandVariableReferences(const QString &value, bool do_semicolon = false,
- int *pos = 0);
- void doVariableReplace(QString *str);
- QStringList evaluateExpandFunction(const QString &function, const QString &arguments);
+ ProStringList expandVariableReferences(const ProString &value, int *pos = 0, bool joined = false);
+ ProStringList expandVariableReferences(const ushort *&tokPtr, int sizeHint = 0, bool joined = false);
+ ProStringList evaluateExpandFunction(const ProString &function, const ProString &arguments);
+ ProStringList evaluateExpandFunction(const ProString &function, const ushort *&tokPtr);
+ ProStringList evaluateExpandFunction(const ProString &function, const ProStringList &args);
QString format(const char *format) const;
void logMessage(const QString &msg) const;
void errorMessage(const QString &msg) const;
QString resolvePath(const QString &fileName) const
{ return IoUtils::resolvePath(currentDirectory(), fileName); }
- ProItem::ProItemReturn evaluateConditionalFunction(const QString &function, const QString &arguments);
+ VisitReturn evaluateConditionalFunction(const ProString &function, const ProString &arguments);
+ VisitReturn evaluateConditionalFunction(const ProString &function, const ushort *&tokPtr);
+ VisitReturn evaluateConditionalFunction(const ProString &function, const ProStringList &args);
ProFile *parsedProFile(const QString &fileName, bool cache,
const QString &contents = QString());
bool evaluateFileDirect(const QString &fileName, ProFileEvaluator::EvalFileType type);
bool evaluateFile(const QString &fileName);
bool evaluateFeatureFile(const QString &fileName,
- QHash<QString, QStringList> *values = 0, FunctionDefs *defs = 0);
+ QHash<ProString, ProStringList> *values = 0, FunctionDefs *defs = 0);
bool evaluateFileInto(const QString &fileName,
- QHash<QString, QStringList> *values, FunctionDefs *defs);
+ QHash<ProString, ProStringList> *values, FunctionDefs *defs);
- static inline ProItem::ProItemReturn returnBool(bool b)
- { return b ? ProItem::ReturnTrue : ProItem::ReturnFalse; }
+ static ALWAYS_INLINE VisitReturn returnBool(bool b)
+ { return b ? ReturnTrue : ReturnFalse; }
- QList<QStringList> prepareFunctionArgs(const QString &arguments);
- QStringList evaluateFunction(ProBlock *funcPtr, const QList<QStringList> &argumentsList, bool *ok);
+ QList<ProStringList> prepareFunctionArgs(const ushort *&tokPtr);
+ QList<ProStringList> prepareFunctionArgs(const ProString &arguments);
+ ProStringList evaluateFunction(const FunctionDef &func, const QList<ProStringList> &argumentsList, bool *ok);
+ VisitReturn evaluateBoolFunction(const FunctionDef &func, const QList<ProStringList> &argumentsList,
+ const ProString &function);
QStringList qmakeMkspecPaths() const;
QStringList qmakeFeaturePaths() const;
- struct State {
- bool condition;
- bool prevCondition;
- } m_sts;
- bool m_invertNext; // Short-lived, so not in State
- bool m_hadCondition; // Nested calls set it on return, so no need for it to be in State
int m_skipLevel;
+ int m_loopLevel; // To report unexpected break() and next()s
bool m_cumulative;
QStack<ProFile*> m_profileStack; // To handle 'include(a.pri), so we can track back to 'a.pro' when finished with 'a.pri'
- struct ProLoop {
- QString variable;
- QStringList oldVarVal;
- QStringList list;
- int index;
- bool infinite;
- };
- QStack<ProLoop> m_loopStack;
+ QStack<QString> m_stringStack; // To handle token string refcounting
QString m_outputDir;
int m_listCount;
- bool m_definingTest;
- QString m_definingFunc;
FunctionDefs m_functionDefs;
- QStringList m_returnValue;
- QStack<QHash<QString, QStringList> > m_valuemapStack; // VariableName must be us-ascii, the content however can be non-us-ascii.
- QHash<const ProFile*, QHash<QString, QStringList> > m_filevaluemap; // Variables per include file
+ ProStringList m_returnValue;
+ QStack<QHash<ProString, ProStringList> > m_valuemapStack; // VariableName must be us-ascii, the content however can be non-us-ascii.
+ QHash<const ProFile*, QHash<ProString, ProStringList> > m_filevaluemap; // Variables per include file
+ QString m_tmp1, m_tmp2, m_tmp3, m_tmp[2]; // Temporaries for efficient toQString
QStringList m_addUserConfigCmdArgs;
QStringList m_removeUserConfigCmdArgs;
ProFileOption *m_option;
enum ExpandFunc {
- E_MEMBER=1, E_FIRST, E_LAST, E_CAT, E_FROMFILE, E_EVAL, E_LIST,
+ E_MEMBER=1, E_FIRST, E_LAST, E_SIZE, E_CAT, E_FROMFILE, E_EVAL, E_LIST,
E_SPRINTF, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION,
E_FIND, E_SYSTEM, E_UNIQUE, E_QUOTE, E_ESCAPE_EXPAND,
E_UPPER, E_LOWER, E_FILES, E_PROMPT, E_RE_ESCAPE,
T_REQUIRES=1, T_GREATERTHAN, T_LESSTHAN, T_EQUALS,
T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM,
T_RETURN, T_BREAK, T_NEXT, T_DEFINED, T_CONTAINS, T_INFILE,
- T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_MESSAGE, T_IF,
- T_FOR, T_DEFINE_TEST, T_DEFINE_REPLACE
+ T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_MESSAGE, T_IF
};
enum VarName {
};
#if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
-Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::State, Q_PRIMITIVE_TYPE);
-Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::ProLoop, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::BlockCursor, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::BlockScope, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::Context, Q_PRIMITIVE_TYPE);
#endif
static struct {
QString field_sep;
- QString deppath;
- QString incpath;
QString strelse;
QString strtrue;
QString strfalse;
QString strmac9;
QString strmac;
QString strwin32;
- QString strCONFIG;
- QString strARGS;
+ ProString strCONFIG;
+ ProString strARGS;
QString strDot;
QString strDotDot;
+ QString strfor;
QString strever;
QString strforever;
- QString strTEMPLATE;
- QString strQMAKE_DIR_SEP;
+ QString strdefineTest;
+ QString strdefineReplace;
+ ProString strTEMPLATE;
+ ProString strQMAKE_DIR_SEP;
QHash<QString, int> expands;
- QHash<QString, int> functions;
- QHash<QString, int> varList;
- QHash<QString, QString> varMap;
+ QHash<ProString, int> functions;
+ QHash<ProString, int> varList;
+ QHash<ProString, ProString> varMap;
QRegExp reg_variableName;
- QStringList fakeValue;
+ ProStringList fakeValue;
} statics;
void ProFileEvaluator::Private::initStatics()
return;
statics.field_sep = QLatin1String(" ");
- statics.deppath = QLatin1String("DEPENDPATH");
- statics.incpath = QLatin1String("INCLUDEPATH");
statics.strelse = QLatin1String("else");
statics.strtrue = QLatin1String("true");
statics.strfalse = QLatin1String("false");
statics.strmac9 = QLatin1String("mac9");
statics.strmac = QLatin1String("mac");
statics.strwin32 = QLatin1String("win32");
- statics.strCONFIG = QLatin1String("CONFIG");
- statics.strARGS = QLatin1String("ARGS");
+ statics.strCONFIG = ProString("CONFIG");
+ statics.strARGS = ProString("ARGS");
statics.strDot = QLatin1String(".");
statics.strDotDot = QLatin1String("..");
+ statics.strfor = QLatin1String("for");
statics.strever = QLatin1String("ever");
statics.strforever = QLatin1String("forever");
- statics.strTEMPLATE = QLatin1String("TEMPLATE");
- statics.strQMAKE_DIR_SEP = QLatin1String("QMAKE_DIR_SEP");
+ statics.strdefineTest = QLatin1String("defineTest");
+ statics.strdefineReplace = QLatin1String("defineReplace");
+ statics.strTEMPLATE = ProString("TEMPLATE");
+ statics.strQMAKE_DIR_SEP = ProString("QMAKE_DIR_SEP");
statics.reg_variableName.setPattern(QLatin1String("\\$\\(.*\\)"));
statics.reg_variableName.setMinimal(true);
{ "member", E_MEMBER },
{ "first", E_FIRST },
{ "last", E_LAST },
+ { "size", E_SIZE },
{ "cat", E_CAT },
{ "fromfile", E_FROMFILE },
{ "eval", E_EVAL },
{ "message", T_MESSAGE },
{ "warning", T_MESSAGE },
{ "error", T_MESSAGE },
- { "for", T_FOR },
- { "defineTest", T_DEFINE_TEST },
- { "defineReplace", T_DEFINE_REPLACE }
};
for (unsigned i = 0; i < sizeof(testInits)/sizeof(testInits[0]); ++i)
- statics.functions.insert(QLatin1String(testInits[i].name), testInits[i].func);
+ statics.functions.insert(ProString(testInits[i].name), testInits[i].func);
static const char * const names[] = {
"LITERAL_DOLLAR", "LITERAL_HASH", "LITERAL_WHITESPACE",
"_DATE_", "_QMAKE_CACHE_"
};
for (unsigned i = 0; i < sizeof(names)/sizeof(names[0]); ++i)
- statics.varList.insert(QLatin1String(names[i]), i);
+ statics.varList.insert(ProString(names[i]), i);
static const struct {
const char * const oldname, * const newname;
{ "QMAKE_FRAMEWORKDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS" }
};
for (unsigned i = 0; i < sizeof(mapInits)/sizeof(mapInits[0]); ++i)
- statics.varMap.insert(QLatin1String(mapInits[i].oldname),
- QLatin1String(mapInits[i].newname));
+ statics.varMap.insert(ProString(mapInits[i].oldname),
+ ProString(mapInits[i].newname));
}
-QString ProFileEvaluator::Private::map(const QString &var)
+ProString ProFileEvaluator::Private::map(const ProString &var)
{
return statics.varMap.value(var, var);
}
m_parsePreAndPostFiles = true;
// Evaluator state
- m_sts.condition = false;
- m_sts.prevCondition = false;
- m_invertNext = false;
m_skipLevel = 0;
- m_definingFunc.clear();
+ m_loopLevel = 0;
m_listCount = 0;
- m_valuemapStack.push(QHash<QString, QStringList>());
+ m_valuemapStack.push(QHash<ProString, ProStringList>());
}
ProFileEvaluator::Private::~Private()
{
- clearFunctions(&m_functionDefs);
}
////////// Parser ///////////
file.close();
m_lineNo = 1;
m_profileStack.push(pro);
- bool ret = readInternal(pro, content, (ushort*)content.data());
+ bool ret = readInternal(pro->itemsRef(), content);
m_profileStack.pop();
return ret;
}
bool ProFileEvaluator::Private::read(ProFile *pro, const QString &content)
{
- QString buf;
- buf.reserve(content.size());
m_lineNo = 1;
m_profileStack.push(pro);
- bool ret = readInternal(pro, content, (ushort*)buf.data());
+ bool ret = readInternal(pro->itemsRef(), content);
m_profileStack.pop();
return ret;
}
-bool ProFileEvaluator::Private::read(ProBlock *pro, const QString &content)
+bool ProFileEvaluator::Private::read(QString *out, const QString &content)
{
- QString buf;
- buf.reserve(content.size());
m_lineNo = 0;
- return readInternal(pro, content, (ushort*)buf.data());
+ return readInternal(out, content);
+}
+
+void ProFileEvaluator::Private::putTok(ushort *&tokPtr, ushort tok)
+{
+ *tokPtr++ = tok;
+}
+
+void ProFileEvaluator::Private::putBlockLen(ushort *&tokPtr, uint len)
+{
+ *tokPtr++ = (ushort)len;
+ *tokPtr++ = (ushort)(len >> 16);
+}
+
+void ProFileEvaluator::Private::putBlock(ushort *&tokPtr, const ushort *buf, uint len)
+{
+ memcpy(tokPtr, buf, len * 2);
+ tokPtr += len;
+}
+
+void ProFileEvaluator::Private::putHashStr(ushort *&pTokPtr, const ushort *buf, uint len)
+{
+ uint hash = ProString::hash((const QChar *)buf, len);
+ ushort *tokPtr = pTokPtr;
+ *tokPtr++ = (ushort)hash;
+ *tokPtr++ = (ushort)(hash >> 16);
+ *tokPtr++ = (ushort)len;
+ memcpy(tokPtr, buf, len * 2);
+ pTokPtr = tokPtr + len;
+}
+
+void ProFileEvaluator::Private::finalizeHashStr(ushort *buf, uint len)
+{
+ buf[-4] = TokHashLiteral;
+ buf[-1] = len;
+ uint hash = ProString::hash((const QChar *)buf, len);
+ buf[-3] = (ushort)hash;
+ buf[-2] = (ushort)(hash >> 16);
}
// We know that the buffer cannot grow larger than the input string,
// and the read() functions rely on it.
-bool ProFileEvaluator::Private::readInternal(ProBlock *pro, const QString &in, ushort *buf)
+bool ProFileEvaluator::Private::readInternal(QString *out, const QString &in)
{
+ // Final precompiled token stream buffer
+ QString tokBuff;
+ // Worst-case size calculations:
+ // - line marker adds 1 (2-nl) to 1st token of each line
+ // - empty assignment "A=":2 =>
+ // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) +
+ // TokValueTerminator(1) == 7 (8)
+ // - non-empty assignment "A=B C":5 =>
+ // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) +
+ // TokLiteral(1) + len(1) + "B"(1) +
+ // TokLiteral(1) + len(1) + "C"(1) + TokValueTerminator(1) == 13 (14)
+ // - variable expansion: "$$f":3 =>
+ // TokVariable(1) + hash(2) + len(1) + "f"(1) = 5
+ // - function expansion: "$$f()":5 =>
+ // TokFuncName(1) + hash(2) + len(1) + "f"(1) + TokFuncTerminator(1) = 6
+ // - scope: "X:":2 =>
+ // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokCondition(1) +
+ // TokBranch(1) + len(2) + ... + len(2) + ... == 10
+ // - test: "X():":4 =>
+ // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokTestCall(1) + TokFuncTerminator(1) +
+ // TokBranch(1) + len(2) + ... + len(2) + ... == 11
+ // - "for(A,B):":9 =>
+ // TokForLoop(1) + hash(2) + len(1) + "A"(1) +
+ // len(2) + TokLiteral(1) + len(1) + "B"(1) + TokValueTerminator(1) +
+ // len(2) + ... + TokTerminator(1) == 14 (15)
+ tokBuff.reserve((in.size() + 1) * 5);
+ ushort *tokPtr = (ushort *)tokBuff.constData(); // Current writing position
+
+ // Expression precompiler buffer.
+ QString xprBuff;
+ xprBuff.reserve(tokBuff.capacity()); // Excessive, but simple
+ ushort *buf = (ushort *)xprBuff.constData();
+
// Parser state
- m_blockstack.push(BlockCursor(pro));
+ m_blockstack.resize(m_blockstack.size() + 1);
+
+ QStack<ParseCtx> xprStack;
+ xprStack.reserve(10);
// We rely on QStrings being null-terminated, so don't maintain a global end pointer.
const ushort *cur = (const ushort *)in.unicode();
+ m_canElse = false;
freshLine:
- ProVariable *currAssignment = 0;
- ushort *ptr = buf;
+ m_state = StNew;
+ m_invert = false;
+ m_operator = NoOperator;
+ m_markLine = m_lineNo;
+ Context context = CtxTest;
int parens = 0;
+ int argc = 0;
+ int litCount = 0;
+ int expCount = 0;
bool inError = false;
- bool putSpace = false;
+ bool putSpace = false; // Only ever true inside quoted string
+ bool lineMarked = true; // For in-expression markers
+ ushort needSep = 0; // Complementary to putSpace: separator outside quotes
ushort quote = 0;
+ ushort term = 0;
+
+ ushort *ptr = buf;
+ ptr += 4;
+ ushort *xprPtr = ptr;
+
+#define FLUSH_LHS_LITERAL(setSep) \
+ do { \
+ if ((tlen = ptr - xprPtr)) { \
+ if (needSep) \
+ goto extraChars; \
+ finalizeHashStr(xprPtr, tlen); \
+ if (setSep) \
+ needSep = TokNewStr; \
+ } else { \
+ ptr -= 4; \
+ if (setSep && ptr != buf) \
+ needSep = TokNewStr; \
+ } \
+ } while (0)
+
+#define FLUSH_RHS_LITERAL(setSep) \
+ do { \
+ if ((tlen = ptr - xprPtr)) { \
+ xprPtr[-2] = TokLiteral | needSep; \
+ xprPtr[-1] = tlen; \
+ if (setSep) \
+ needSep = TokNewStr; \
+ litCount++; \
+ } else { \
+ ptr -= 2; \
+ if (setSep && ptr != ((context == CtxValue) ? tokPtr : buf)) \
+ needSep = TokNewStr; \
+ } \
+ } while (0)
+
+#define FLUSH_LITERAL(setSep) \
+ do { \
+ if (context == CtxTest) \
+ FLUSH_LHS_LITERAL(setSep); \
+ else \
+ FLUSH_RHS_LITERAL(setSep); \
+ } while (0)
+
forever {
ushort c;
// First, skip leading whitespace
for (;; ++cur) {
c = *cur;
- if (c == '\n' || !c) { // Entirely empty line (sans whitespace)
- if (currAssignment) {
- finalizeVariable(currAssignment, buf, ptr);
- currAssignment = 0;
- } else {
- updateItem(buf, ptr);
- }
- finalizeBlock();
- if (c) {
- ++cur;
- ++m_lineNo;
- goto freshLine;
- }
- m_block.reset();
- m_blockstack.clear(); // FIXME: should actually check the state here
- return true;
- }
- if (c != ' ' && c != '\t' && c != '\r')
+ if (c == '\n') {
+ ++cur;
+ goto flushLine;
+ } else if (!c) {
+ goto flushLine;
+ } else if (c != ' ' && c != '\t' && c != '\r') {
break;
+ }
}
// Then strip comments. Yep - no escaping is possible.
if (!inError) {
// Finally, do the tokenization
- if (!currAssignment) {
- newItem:
- do {
- if (cur == end)
- goto lineEnd;
- c = *cur++;
- } while (c == ' ' || c == '\t');
- forever {
- if (c == '"') {
- quote = '"' - quote;
- } else if (!quote) {
- if (c == '(') {
- ++parens;
- } else if (c == ')') {
- --parens;
- } else if (!parens) {
- if (c == ':') {
- updateItem(buf, ptr);
- enterScope(false);
- nextItem:
- ptr = buf;
- putSpace = false;
- goto newItem;
- }
- if (c == '{') {
- updateItem(buf, ptr);
- enterScope(true);
- goto nextItem;
+ ushort tok, rtok;
+ int tlen;
+ newToken:
+ do {
+ if (cur == end)
+ goto lineEnd;
+ c = *cur++;
+ } while (c == ' ' || c == '\t');
+ forever {
+ if (c == '$') {
+ if (*cur == '$') { // may be EOF, EOL, WS or '#' if past end
+ cur++;
+ if (putSpace) {
+ putSpace = false;
+ *ptr++ = ' ';
+ }
+ tlen = ptr - xprPtr;
+ if (context == CtxTest) {
+ if (needSep)
+ goto extraChars;
+ if (tlen)
+ finalizeHashStr(xprPtr, tlen);
+ else
+ ptr -= 4;
+ } else {
+ if (tlen) {
+ xprPtr[-2] = TokLiteral | needSep;
+ xprPtr[-1] = tlen;
+ needSep = 0;
+ litCount++;
+ } else {
+ ptr -= 2;
}
- if (c == '}') {
- updateItem(buf, ptr);
- leaveScope();
- goto nextItem;
+ }
+ if (!lineMarked) {
+ lineMarked = true;
+ *ptr++ = TokLine;
+ *ptr++ = (ushort)m_lineNo;
+ }
+ term = 0;
+ tok = TokVariable;
+ c = *cur;
+ if (c == '[') {
+ ptr += 2;
+ tok = TokProperty;
+ term = ']';
+ c = *++cur;
+ } else if (c == '{') {
+ ptr += 4;
+ term = '}';
+ c = *++cur;
+ } else if (c == '(') {
+ // FIXME: could/should expand this immediately
+ ptr += 2;
+ tok = TokEnvVar;
+ term = ')';
+ c = *++cur;
+ } else {
+ ptr += 4;
+ }
+ xprPtr = ptr;
+ rtok = tok;
+ while ((c & 0xFF00) || c == '.' || c == '_' ||
+ (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9')) {
+ *ptr++ = c;
+ if (++cur == end) {
+ c = 0;
+ goto notfunc;
}
- if (c == '=') {
- if ((currAssignment = startVariable(buf, ptr))) {
- ptr = buf;
- putSpace = false;
- break;
- }
- ptr = buf;
- inError = true;
- goto skip;
+ c = *cur;
+ }
+ if (tok == TokVariable && c == '(')
+ tok = TokFuncName;
+ notfunc:
+ if (quote)
+ tok |= TokQuoted;
+ tok |= needSep;
+ needSep = 0;
+ expCount++;
+ tlen = ptr - xprPtr;
+ if (rtok == TokVariable) {
+ xprPtr[-4] = tok;
+ uint hash = ProString::hash((const QChar *)xprPtr, tlen);
+ xprPtr[-3] = (ushort)hash;
+ xprPtr[-2] = (ushort)(hash >> 16);
+ } else {
+ xprPtr[-2] = tok;
+ }
+ xprPtr[-1] = tlen;
+ if ((tok & TokMask) == TokFuncName) {
+ cur++;
+ funcCall:
+ {
+ xprStack.resize(xprStack.size() + 1);
+ ParseCtx &top = xprStack.top();
+ top.parens = parens;
+ top.quote = quote;
+ top.terminator = term;
+ top.context = context;
+ top.argc = argc;
+ top.litCount = litCount;
+ top.expCount = expCount;
}
- if (c == '|' || c == '!') {
- updateItem(buf, ptr);
- insertOperator(c);
- goto nextItem;
+ parens = 0;
+ quote = 0;
+ term = 0;
+ argc = 1;
+ context = CtxArgs;
+ nextToken:
+ ptr += (context == CtxTest) ? 4 : 2;
+ xprPtr = ptr;
+ goto newToken;
+ }
+ if (term) {
+ cur++;
+ checkTerm:
+ if (c != term) {
+ logMessage(format("Missing %1 terminator [found %2]")
+ .arg(QChar(term))
+ .arg(c ? QString(c) : QString::fromLatin1("end-of-line")));
+ return false;
}
}
+ joinToken:
+ ptr += (context == CtxTest) ? 4 : 2;
+ xprPtr = ptr;
+ goto nextChr;
}
-
- if (putSpace) {
- putSpace = false;
- *ptr++ = ' ';
+ } else if (c == '\\') {
+ static const char symbols[] = "[]{}()$\\'\"";
+ ushort c2 = *cur;
+ if (!(c2 & 0xff00) && strchr(symbols, c2)) {
+ c = c2;
+ cur++;
}
- *ptr++ = c;
-
- forever {
- if (cur == end)
- goto lineEnd;
- c = *cur++;
- if (c != ' ' && c != '\t')
- break;
+ } else if (quote) {
+ if (c == quote) {
+ quote = 0;
+ if (putSpace) {
+ putSpace = false;
+ *ptr++ = ' ';
+ }
+ goto nextChr;
+ } else if (c == ' ' || c == '\t') {
putSpace = true;
+ goto nextChr;
+ } else if (c == '!' && ptr == xprPtr && context == CtxTest) {
+ m_invert ^= true;
+ goto nextChr;
+ }
+ } else if (c == '\'' || c == '"') {
+ quote = c;
+ goto nextChr;
+ } else if (c == ' ' || c == '\t') {
+ FLUSH_LITERAL(true);
+ goto nextToken;
+ } else if (context == CtxArgs) {
+ // Function arg context
+ if (c == '(') {
+ ++parens;
+ } else if (c == ')') {
+ if (--parens < 0) {
+ FLUSH_RHS_LITERAL(false);
+ *ptr++ = TokFuncTerminator;
+ int theargc = argc;
+ {
+ ParseCtx &top = xprStack.top();
+ parens = top.parens;
+ quote = top.quote;
+ term = top.terminator;
+ context = top.context;
+ argc = top.argc;
+ litCount = top.litCount;
+ expCount = top.expCount;
+ xprStack.resize(xprStack.size() - 1);
+ }
+ if (term == ':') {
+ finalizeCall(tokPtr, buf, ptr, theargc);
+ needSep = TokNewStr;
+ goto nextItem;
+ } else if (term == '}') {
+ c = (cur == end) ? 0 : *cur++;
+ needSep = 0;
+ goto checkTerm;
+ } else {
+ Q_ASSERT(!term);
+ needSep = 0;
+ goto joinToken;
+ }
+ }
+ } else if (!parens && c == ',') {
+ FLUSH_RHS_LITERAL(false);
+ *ptr++ = TokArgSeparator;
+ argc++;
+ needSep = 0;
+ goto nextToken;
+ }
+ } else if (context == CtxTest) {
+ // Test or LHS context
+ if (c == '(') {
+ FLUSH_LHS_LITERAL(false);
+ if (ptr == buf) {
+ logMessage(format("Opening parenthesis without prior test name."));
+ inError = true;
+ goto skip;
+ }
+ *ptr++ = TokTestCall;
+ term = ':';
+ needSep = 0;
+ goto funcCall;
+ } else if (c == '!' && ptr == xprPtr) {
+ m_invert ^= true;
+ goto nextChr;
+ } else if (c == ':') {
+ FLUSH_LHS_LITERAL(false);
+ finalizeCond(tokPtr, buf, ptr);
+ if (m_state == StNew)
+ logMessage(format("And operator without prior condition."));
+ else
+ m_operator = AndOperator;
+ nextItem:
+ ptr = buf;
+ needSep = 0;
+ goto nextToken;
+ } else if (c == '|') {
+ FLUSH_LHS_LITERAL(false);
+ finalizeCond(tokPtr, buf, ptr);
+ if (m_state != StCond)
+ logMessage(format("Or operator without prior condition."));
+ else
+ m_operator = OrOperator;
+ goto nextItem;
+ } else if (c == '{') {
+ FLUSH_LHS_LITERAL(false);
+ finalizeCond(tokPtr, buf, ptr);
+ flushCond(tokPtr);
+ ++m_blockstack.top().braceLevel;
+ goto nextItem;
+ } else if (c == '}') {
+ FLUSH_LHS_LITERAL(false);
+ finalizeCond(tokPtr, buf, ptr);
+ flushScopes(tokPtr);
+ if (!m_blockstack.top().braceLevel) {
+ logMessage(format("Excess closing brace."));
+ } else if (!--m_blockstack.top().braceLevel
+ && m_blockstack.count() != 1) {
+ leaveScope(tokPtr);
+ m_state = StNew;
+ m_canElse = false;
+ m_markLine = m_lineNo;
+ }
+ goto nextItem;
+ } else if (c == '+') {
+ tok = TokAppend;
+ goto do2Op;
+ } else if (c == '-') {
+ tok = TokRemove;
+ goto do2Op;
+ } else if (c == '*') {
+ tok = TokAppendUnique;
+ goto do2Op;
+ } else if (c == '~') {
+ tok = TokReplace;
+ do2Op:
+ if (*cur == '=') {
+ cur++;
+ goto doOp;
+ }
+ } else if (c == '=') {
+ tok = TokAssign;
+ doOp:
+ FLUSH_LHS_LITERAL(false);
+ flushCond(tokPtr);
+ putLineMarker(tokPtr);
+ if (!(tlen = ptr - buf)) {
+ logMessage(format("Assignment operator without prior variable name."));
+ inError = true;
+ goto skip;
+ }
+ putBlock(tokPtr, buf, tlen);
+ putTok(tokPtr, tok);
+ context = CtxValue;
+ ptr = ++tokPtr;
+ litCount = expCount = 0;
+ needSep = 0;
+ goto nextToken;
}
}
- } // !currAssignment
-
- do {
- if (cur == end)
- goto lineEnd;
- c = *cur++;
- } while (c == ' ' || c == '\t');
- forever {
if (putSpace) {
putSpace = false;
*ptr++ = ' ';
}
*ptr++ = c;
-
- forever {
- if (cur == end)
- goto lineEnd;
- c = *cur++;
- if (c != ' ' && c != '\t')
- break;
- putSpace = true;
- }
+ nextChr:
+ if (cur == end)
+ goto lineEnd;
+ c = *cur++;
}
+
lineEnd:
if (lineCont) {
- putSpace = (ptr != buf);
+ if (quote) {
+ putSpace = true;
+ } else {
+ FLUSH_LITERAL(true);
+ ptr += (context == CtxTest) ? 4 : 2;
+ xprPtr = ptr;
+ }
} else {
- if (currAssignment) {
- finalizeVariable(currAssignment, buf, ptr);
- currAssignment = 0;
+ c = '\n';
+ cur = cptr;
+ flushLine:
+ FLUSH_LITERAL(false);
+ if (quote) {
+ logMessage(format("Missing closing %1 quote").arg(QChar(quote)));
+ return false;
+ }
+ if (!xprStack.isEmpty()) {
+ logMessage(format("Missing closing parenthesis in function call"));
+ return false;
+ }
+ if (context == CtxValue) {
+ tokPtr[-1] = litCount ? litCount + expCount : 0;
+ tokPtr = ptr;
+ putTok(tokPtr, TokValueTerminator);
} else {
- updateItem(buf, ptr);
+ finalizeCond(tokPtr, buf, ptr);
}
- ptr = buf;
- putSpace = false;
+ if (!c) {
+ flushScopes(tokPtr);
+ if (m_blockstack.size() > 1)
+ logMessage(format("Missing closing brace(s)."));
+ while (m_blockstack.size())
+ leaveScope(tokPtr);
+ xprBuff.clear();
+ *out = QString(tokBuff.constData(), tokPtr - (ushort *)tokBuff.constData());
+ return true;
+ }
+ ++m_lineNo;
+ goto freshLine;
}
} // !inError
skip:
if (!lineCont) {
- finalizeBlock();
cur = cptr;
++m_lineNo;
goto freshLine;
}
+ lineMarked = false;
ignore:
cur = cptr;
++m_lineNo;
}
+
+#undef FLUSH_LITERAL
+#undef FLUSH_LHS_LITERAL
+#undef FLUSH_RHS_LITERAL
+
+ extraChars:
+ logMessage(format("Extra characters after test expression."));
+ return false;
}
-void ProFileEvaluator::Private::finalizeBlock()
+void ProFileEvaluator::Private::putLineMarker(ushort *&tokPtr)
{
- if (m_blockstack.top().block->blockKind() & ProBlock::SingleLine)
- leaveScope();
- m_block.reset();
+ if (m_markLine) {
+ *tokPtr++ = TokLine;
+ *tokPtr++ = (ushort)m_markLine;
+ m_markLine = 0;
+ }
}
-ProVariable *ProFileEvaluator::Private::startVariable(ushort *uc, ushort *ptr)
+void ProFileEvaluator::Private::enterScope(ushort *&tokPtr, bool special, ScopeState state)
{
- ProVariable::VariableOperator opkind;
-
- if (ptr == uc) // Line starting with '=', like a conflict marker
- return 0;
+ m_blockstack.resize(m_blockstack.size() + 1);
+ m_blockstack.top().special = special;
+ m_blockstack.top().start = tokPtr;
+ tokPtr += 2;
+ m_state = state;
+ m_canElse = false;
+ if (special)
+ m_markLine = m_lineNo;
+}
- switch (*(ptr - 1)) {
- case '+':
- --ptr;
- opkind = ProVariable::AddOperator;
- break;
- case '-':
- --ptr;
- opkind = ProVariable::RemoveOperator;
- break;
- case '*':
- --ptr;
- opkind = ProVariable::UniqueAddOperator;
- break;
- case '~':
- --ptr;
- opkind = ProVariable::ReplaceOperator;
- break;
- default:
- opkind = ProVariable::SetOperator;
- goto skipTrunc;
+void ProFileEvaluator::Private::leaveScope(ushort *&tokPtr)
+{
+ if (m_blockstack.top().inBranch) {
+ // Put empty else block
+ putBlockLen(tokPtr, 0);
}
+ if (ushort *start = m_blockstack.top().start) {
+ putTok(tokPtr, TokTerminator);
+ uint len = tokPtr - start - 2;
+ start[0] = (ushort)len;
+ start[1] = (ushort)(len >> 16);
+ }
+ m_blockstack.resize(m_blockstack.size() - 1);
+}
- if (ptr == uc) // Line starting with manipulation operator
- return 0;
- if (*(ptr - 1) == ' ')
- --ptr;
-
- skipTrunc:
- ProVariable *variable = new ProVariable(map(QString((QChar*)uc, ptr - uc)));
- variable->setLineNumber(m_lineNo);
- variable->setVariableOperator(opkind);
- return variable;
+void ProFileEvaluator::Private::flushScopes(ushort *&tokPtr)
+{
+ if (m_state == StNew) {
+ while (!m_blockstack.top().braceLevel && m_blockstack.size() > 1)
+ leaveScope(tokPtr);
+ if (m_blockstack.top().inBranch) {
+ m_blockstack.top().inBranch = false;
+ // Put empty else block
+ putBlockLen(tokPtr, 0);
+ }
+ m_canElse = false;
+ }
}
-void ProFileEvaluator::Private::finalizeVariable(ProVariable *variable, ushort *uc, ushort *ptr)
+void ProFileEvaluator::Private::flushCond(ushort *&tokPtr)
{
- variable->setValue(QString((QChar*)uc, ptr - uc));
+ if (m_state == StCond) {
+ putTok(tokPtr, TokBranch);
+ m_blockstack.top().inBranch = true;
+ enterScope(tokPtr, false, StNew);
+ } else {
+ flushScopes(tokPtr);
+ }
+}
- m_blockstack.top().append(variable);
+void ProFileEvaluator::Private::finalizeTest(ushort *&tokPtr)
+{
+ flushScopes(tokPtr);
+ putLineMarker(tokPtr);
+ if (m_operator != NoOperator) {
+ putTok(tokPtr, (m_operator == AndOperator) ? TokAnd : TokOr);
+ m_operator = NoOperator;
+ }
+ if (m_invert) {
+ putTok(tokPtr, TokNot);
+ m_invert = false;
+ }
+ m_state = StCond;
+ m_canElse = true;
}
-void ProFileEvaluator::Private::insertOperator(const char op)
+void ProFileEvaluator::Private::finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr)
{
- ProOperator::OperatorKind opkind;
- switch (op) {
- case '!':
- opkind = ProOperator::NotOperator;
- break;
- case '|':
- opkind = ProOperator::OrOperator;
- break;
- default:
- opkind = ProOperator::OrOperator;
+ if (ptr == uc)
+ return;
+
+ // Check for magic tokens
+ if (*uc == TokHashLiteral) {
+ uint nlen = uc[3];
+ ushort *uce = uc + 4 + nlen;
+ if (uce == ptr) {
+ m_tmp1.setRawData((QChar *)uc + 4, nlen);
+ if (!m_tmp1.compare(statics.strelse, Qt::CaseInsensitive)) {
+ if (m_invert || m_operator != NoOperator) {
+ logMessage(format("Unexpected operator in front of else."));
+ return;
+ }
+ BlockScope &top = m_blockstack.top();
+ if (m_canElse && (!top.special || top.braceLevel)) {
+ putTok(tokPtr, TokBranch);
+ // Put empty then block
+ putBlockLen(tokPtr, 0);
+ enterScope(tokPtr, false, StCtrl);
+ return;
+ }
+ forever {
+ BlockScope &top = m_blockstack.top();
+ if (top.inBranch && (!top.special || top.braceLevel)) {
+ top.inBranch = false;
+ enterScope(tokPtr, false, StCtrl);
+ return;
+ }
+ if (top.braceLevel || m_blockstack.size() == 1)
+ break;
+ leaveScope(tokPtr);
+ }
+ errorMessage(format("Unexpected 'else'."));
+ return;
+ }
+ }
}
- ProOperator * const proOp = new ProOperator(opkind);
- proOp->setLineNumber(m_lineNo);
- currentBlock().append(proOp);
+ finalizeTest(tokPtr);
+ putBlock(tokPtr, uc, ptr - uc);
+ putTok(tokPtr, TokCondition);
}
-void ProFileEvaluator::Private::enterScope(bool multiLine)
+void ProFileEvaluator::Private::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc)
{
- BlockCursor &parent = currentBlock();
+ // Check for magic tokens
+ if (*uc == TokHashLiteral) {
+ uint nlen = uc[3];
+ ushort *uce = uc + 4 + nlen;
+ if (*uce == TokTestCall) {
+ uce++;
+ m_tmp1.setRawData((QChar *)uc + 4, nlen);
+ const QString *defName;
+ ushort defType;
+ if (m_tmp1 == statics.strfor) {
+ flushCond(tokPtr);
+ putLineMarker(tokPtr);
+ if (m_invert || m_operator == OrOperator) {
+ // '|' could actually work reasonably, but qmake does nonsense here.
+ logMessage(format("Unexpected operator in front of for()."));
+ return;
+ }
+ if (*uce == TokLiteral) {
+ nlen = uce[1];
+ uc = uce + 2 + nlen;
+ if (*uc == TokFuncTerminator) {
+ // for(literal) (only "ever" would be legal if qmake was sane)
+ putTok(tokPtr, TokForLoop);
+ putHashStr(tokPtr, (ushort *)0, (uint)0);
+ putBlockLen(tokPtr, 1 + 3 + nlen + 1);
+ putTok(tokPtr, TokHashLiteral);
+ putHashStr(tokPtr, uce + 2, nlen);
+ didFor:
+ putTok(tokPtr, TokValueTerminator);
+ enterScope(tokPtr, true, StCtrl);
+ return;
+ } else if (*uc == TokArgSeparator && argc == 2) {
+ // for(var, something)
+ uc++;
+ putTok(tokPtr, TokForLoop);
+ putHashStr(tokPtr, uce + 2, nlen);
+ doFor:
+ nlen = ptr - uc;
+ putBlockLen(tokPtr, nlen + 1);
+ putBlock(tokPtr, uc, nlen);
+ goto didFor;
+ }
+ } else if (argc == 1) {
+ // for(non-literal) (this wouldn't be here if qmake was sane)
+ putTok(tokPtr, TokForLoop);
+ putHashStr(tokPtr, (ushort *)0, (uint)0);
+ uc = uce;
+ goto doFor;
+ }
+ logMessage(format("Syntax is for(var, list), for(var, forever) or for(ever)."));
+ return;
+ } else if (m_tmp1 == statics.strdefineReplace) {
+ defName = &statics.strdefineReplace;
+ defType = TokReplaceDef;
+ goto deffunc;
+ } else if (m_tmp1 == statics.strdefineTest) {
+ defName = &statics.strdefineTest;
+ defType = TokTestDef;
+ deffunc:
+ flushScopes(tokPtr);
+ putLineMarker(tokPtr);
+ if (m_invert) {
+ logMessage(format("Unexpected operator in front of function definition."));
+ return;
+ }
+ if (*uce == TokLiteral) {
+ uint nlen = uce[1];
+ if (uce[nlen + 2] == TokFuncTerminator) {
+ if (m_operator != NoOperator) {
+ putTok(tokPtr, (m_operator == AndOperator) ? TokAnd : TokOr);
+ m_operator = NoOperator;
+ }
+ putTok(tokPtr, defType);
+ putHashStr(tokPtr, uce + 2, nlen);
+ uc = uce + 2 + nlen + 1;
+ enterScope(tokPtr, true, StCtrl);
+ return;
+ }
+ }
+ logMessage(format("%1(function) requires one literal argument.").arg(*defName));
+ return;
+ }
+ }
+ }
- ProBlock *block = new ProBlock();
- block->setLineNumber(m_lineNo);
- if (multiLine)
- block->setBlockKind(ProBlock::ScopeContentsKind);
- else
- block->setBlockKind(ProBlock::ScopeContentsKind|ProBlock::SingleLine);
- m_blockstack.push(BlockCursor(block));
+ finalizeTest(tokPtr);
+ putBlock(tokPtr, uc, ptr - uc);
+}
- parent.block->setBlockKind(ProBlock::ScopeKind);
- parent.append(block);
+//////// Evaluator tools /////////
- m_block.reset();
+uint ProFileEvaluator::Private::getBlockLen(const ushort *&tokPtr)
+{
+ uint len = *tokPtr++;
+ len |= (uint)*tokPtr++ << 16;
+ return len;
}
-void ProFileEvaluator::Private::leaveScope()
+ProString ProFileEvaluator::Private::getStr(const ushort *&tokPtr)
{
- if (m_blockstack.count() == 1)
- errorMessage(format("Excess closing brace."));
- else
- m_blockstack.pop();
- finalizeBlock();
+ const QString &str(m_stringStack.top());
+ uint len = *tokPtr++;
+ ProString ret(str, tokPtr - (const ushort *)str.constData(), len, NoHash);
+ tokPtr += len;
+ return ret;
}
-ProFileEvaluator::Private::BlockCursor &ProFileEvaluator::Private::currentBlock()
+ProString ProFileEvaluator::Private::getHashStr(const ushort *&tokPtr)
{
- if (!m_block.isValid()) {
- ProBlock *blk = new ProBlock();
- blk->setLineNumber(m_lineNo);
- m_blockstack.top().append(blk);
- m_block.set(blk);
- }
- return m_block;
+ uint hash = getBlockLen(tokPtr);
+ uint len = *tokPtr++;
+ const QString &str(m_stringStack.top());
+ ProString ret(str, tokPtr - (const ushort *)str.constData(), len, hash);
+ tokPtr += len;
+ return ret;
}
-void ProFileEvaluator::Private::updateItem(ushort *uc, ushort *ptr)
+void ProFileEvaluator::Private::skipStr(const ushort *&tokPtr)
{
- if (ptr == uc)
- return;
-
- QString proItem = QString((QChar*)uc, ptr - uc);
-
- ProItem *item;
- if (proItem.endsWith(QLatin1Char(')'))) {
- item = new ProFunction(proItem);
- } else {
- item = new ProCondition(proItem);
- }
- item->setLineNumber(m_lineNo);
- currentBlock().append(item);
+ uint len = *tokPtr++;
+ tokPtr += len;
}
-//////// Evaluator tools /////////
+void ProFileEvaluator::Private::skipHashStr(const ushort *&tokPtr)
+{
+ tokPtr += 2;
+ uint len = *tokPtr++;
+ tokPtr += len;
+}
-QStringList ProFileEvaluator::Private::split_value_list(const QString &vals)
+// FIXME: this should not build new strings for direct sections.
+// Note that the E_SPRINTF and E_LIST implementations rely on the deep copy.
+ProStringList ProFileEvaluator::Private::split_value_list(const QString &vals)
{
QString build;
- QStringList ret;
+ ProStringList ret;
QStack<char> quote;
const ushort SPACE = ' ';
}
if (!parens && quote.isEmpty() && vals_data[x] == SPACE) {
- ret << build;
+ ret << ProString(build, NoHash);
build.clear();
} else {
build += vals_data[x];
}
}
if (!build.isEmpty())
- ret << build;
+ ret << ProString(build, NoHash);
return ret;
}
-static void insertUnique(QStringList *varlist, const QStringList &value)
+static void zipEmpty(ProStringList *value)
+{
+ for (int i = value->size(); --i >= 0;)
+ if (value->at(i).isEmpty())
+ value->remove(i);
+}
+
+static void insertUnique(ProStringList *varlist, const ProStringList &value)
{
- foreach (const QString &str, value)
- if (!varlist->contains(str))
+ foreach (const ProString &str, value)
+ if (!str.isEmpty() && !varlist->contains(str))
varlist->append(str);
}
-static void removeEach(QStringList *varlist, const QStringList &value)
+static void removeAll(ProStringList *varlist, const ProString &value)
{
- foreach (const QString &str, value)
- varlist->removeAll(str);
+ for (int i = varlist->size(); --i >= 0; )
+ if (varlist->at(i) == value)
+ varlist->remove(i);
}
-static void replaceInList(QStringList *varlist,
- const QRegExp ®exp, const QString &replace, bool global)
+static void removeEach(ProStringList *varlist, const ProStringList &value)
{
- for (QStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) {
- if ((*varit).contains(regexp)) {
- (*varit).replace(regexp, replace);
- if ((*varit).isEmpty())
+ foreach (const ProString &str, value)
+ if (!str.isEmpty())
+ removeAll(varlist, str);
+}
+
+static void replaceInList(ProStringList *varlist,
+ const QRegExp ®exp, const QString &replace, bool global, QString &tmp)
+{
+ for (ProStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) {
+ QString val = varit->toQString(tmp);
+ QString copy = val; // Force detach and have a reference value
+ val.replace(regexp, replace);
+ if (!val.isSharedWith(copy)) {
+ if (val.isEmpty()) {
varit = varlist->erase(varit);
- else
+ } else {
+ *varit = ProString(val);
++varit;
+ }
if (!global)
break;
} else {
return string;
}
-static QStringList expandEnvVars(const QStringList &x)
-{
- QStringList ret;
- foreach (const QString &str, x)
- ret << expandEnvVars(str);
- return ret;
-}
-
// This is braindead, but we want qmake compat
static QString fixPathToLocalOS(const QString &str)
{
return string;
}
+static bool isTrue(const ProString &_str, QString &tmp)
+{
+ const QString &str = _str.toQString(tmp);
+ return !str.compare(statics.strtrue, Qt::CaseInsensitive) || str.toInt();
+}
+
//////// Evaluator /////////
-ProItem::ProItemReturn ProFileEvaluator::Private::visitProItem(ProItem *item)
+static ALWAYS_INLINE void addStr(
+ const ProString &str, ProStringList *ret, bool &pending, bool joined)
{
- switch (item->kind()) {
- case ProItem::BlockKind: // This is never a ProFile
- return visitProBlock(static_cast<ProBlock*>(item));
- case ProItem::VariableKind:
- visitProVariable(static_cast<ProVariable*>(item));
- break;
- case ProItem::ConditionKind:
- visitProCondition(static_cast<ProCondition*>(item));
- break;
- case ProItem::FunctionKind:
- return visitProFunction(static_cast<ProFunction*>(item));
- case ProItem::OperatorKind:
- visitProOperator(static_cast<ProOperator*>(item));
- break;
+ if (joined) {
+ ret->last().append(str, &pending);
+ } else {
+ if (!pending) {
+ pending = true;
+ *ret << str;
+ } else {
+ ret->last().append(str);
+ }
}
- return ProItem::ReturnTrue;
}
-ProItem::ProItemReturn ProFileEvaluator::Private::visitProBlock(ProBlock *block)
+static ALWAYS_INLINE void addStrList(
+ const ProStringList &list, ushort tok, ProStringList *ret, bool &pending, bool joined)
{
- if (block->blockKind() & ProBlock::ScopeContentsKind) {
- if (!m_definingFunc.isEmpty()) {
- if (!m_skipLevel || m_cumulative) {
- QHash<QString, ProBlock *> *hash =
- (m_definingTest ? &m_functionDefs.testFunctions
- : &m_functionDefs.replaceFunctions);
- if (ProBlock *def = hash->value(m_definingFunc))
- def->deref();
- hash->insert(m_definingFunc, block);
- block->ref();
- block->setBlockKind(block->blockKind() | ProBlock::FunctionBodyKind);
- }
- m_definingFunc.clear();
- return ProItem::ReturnTrue;
- } else if (!(block->blockKind() & ProBlock::FunctionBodyKind)) {
- if (!m_sts.condition) {
- if (m_skipLevel || m_hadCondition)
- ++m_skipLevel;
+ if (!list.isEmpty()) {
+ if (joined) {
+ ret->last().append(list, &pending, !(tok & TokQuoted));
+ } else {
+ if (tok & TokQuoted) {
+ if (!pending) {
+ pending = true;
+ *ret << ProString();
+ }
+ ret->last().append(list);
} else {
- Q_ASSERT(!m_skipLevel);
+ if (!pending) {
+ pending = true;
+ // Another qmake bizzarity: if nothing is pending and the
+ // first element is empty, it will be eaten
+ if (!list.at(0).isEmpty()) {
+ // The common case
+ *ret += list;
+ return;
+ }
+ } else {
+ ret->last().append(list.at(0));
+ }
+ // This is somewhat slow, but a corner case
+ for (int j = 1; j < list.size(); ++j)
+ *ret << list.at(j);
}
}
- } else {
- m_hadCondition = false;
- if (!m_skipLevel) {
- if (m_sts.condition) {
- m_sts.prevCondition = true;
- m_sts.condition = false;
- }
- } else {
- Q_ASSERT(!m_sts.condition);
+ }
+}
+
+void ProFileEvaluator::Private::evaluateExpression(
+ const ushort *&tokPtr, ProStringList *ret, bool joined)
+{
+ if (joined)
+ *ret << ProString();
+ bool pending = false;
+ forever {
+ ushort tok = *tokPtr++;
+ if (tok & TokNewStr)
+ pending = false;
+ ushort maskedTok = tok & TokMask;
+ switch (maskedTok) {
+ case TokLine:
+ m_lineNo = *tokPtr++;
+ break;
+ case TokLiteral:
+ addStr(getStr(tokPtr), ret, pending, joined);
+ break;
+ case TokHashLiteral:
+ addStr(getHashStr(tokPtr), ret, pending, joined);
+ break;
+ case TokVariable:
+ addStrList(values(map(getHashStr(tokPtr))), tok, ret, pending, joined);
+ break;
+ case TokProperty:
+ addStr(ProString(propertyValue(
+ getStr(tokPtr).toQString(m_tmp1)), NoHash), ret, pending, joined);
+ break;
+ case TokEnvVar:
+ addStrList(split_value_list(QString::fromLocal8Bit(qgetenv(
+ getStr(tokPtr).toQString(m_tmp1).toLatin1().constData()))), tok, ret, pending, joined);
+ break;
+ case TokFuncName: {
+ ProString func = getHashStr(tokPtr);
+ addStrList(evaluateExpandFunction(func, tokPtr), tok, ret, pending, joined);
+ break; }
+ default:
+ tokPtr--;
+ return;
}
}
- ProItem::ProItemReturn rt = ProItem::ReturnTrue;
- for (ProItem *item = block->items(); item; item = item->next()) {
- rt = visitProItem(item);
- if (rt != ProItem::ReturnTrue && rt != ProItem::ReturnFalse) {
- if (rt == ProItem::ReturnLoop) {
- rt = ProItem::ReturnTrue;
- while (visitProLoopIteration())
- for (ProItem *lItem = item; (lItem = lItem->next()); ) {
- rt = visitProItem(lItem);
- if (rt != ProItem::ReturnTrue && rt != ProItem::ReturnFalse) {
- if (rt == ProItem::ReturnNext) {
- rt = ProItem::ReturnTrue;
- break;
- }
- if (rt == ProItem::ReturnBreak)
- rt = ProItem::ReturnTrue;
- goto do_break;
- }
- }
- do_break:
- visitProLoopCleanup();
- }
+}
+
+void ProFileEvaluator::Private::skipExpression(const ushort *&pTokPtr)
+{
+ const ushort *tokPtr = pTokPtr;
+ forever {
+ ushort tok = *tokPtr++;
+ switch (tok) {
+ case TokLine:
+ m_lineNo = *tokPtr++;
+ break;
+ case TokValueTerminator:
+ case TokFuncTerminator:
+ pTokPtr = tokPtr;
+ return;
+ case TokArgSeparator:
break;
+ default:
+ switch (tok & TokMask) {
+ case TokLiteral:
+ case TokProperty:
+ case TokEnvVar:
+ skipStr(tokPtr);
+ break;
+ case TokHashLiteral:
+ case TokVariable:
+ skipHashStr(tokPtr);
+ break;
+ case TokFuncName:
+ skipHashStr(tokPtr);
+ pTokPtr = tokPtr;
+ skipExpression(pTokPtr);
+ tokPtr = pTokPtr;
+ break;
+ default:
+ Q_ASSERT_X(false, "skipExpression", "Unrecognized token");
+ break;
+ }
}
}
- if ((block->blockKind() & ProBlock::ScopeContentsKind)
- && !(block->blockKind() & ProBlock::FunctionBodyKind)) {
- if (m_skipLevel) {
- Q_ASSERT(!m_sts.condition);
- --m_skipLevel;
- } else if (!(block->blockKind() & ProBlock::SingleLine)) {
- // Conditionals contained inside this block may have changed the state.
- // So we reset it here to make an else following us do the right thing.
- m_sts.condition = true;
+}
+
+ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::visitProBlock(
+ const ushort *tokPtr)
+{
+ ProStringList curr;
+ bool okey = true, or_op = false, invert = false;
+ uint blockLen;
+ VisitReturn ret = ReturnTrue;
+ while (ushort tok = *tokPtr++) {
+ switch (tok) {
+ case TokLine:
+ m_lineNo = *tokPtr++;
+ continue;
+ case TokAssign:
+ case TokAppend:
+ case TokAppendUnique:
+ case TokRemove:
+ case TokReplace:
+ visitProVariable(tok, curr, tokPtr);
+ curr.clear();
+ continue;
+ case TokBranch:
+ blockLen = getBlockLen(tokPtr);
+ if (m_cumulative) {
+ if (!okey)
+ m_skipLevel++;
+ ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
+ tokPtr += blockLen;
+ blockLen = getBlockLen(tokPtr);
+ if (!okey)
+ m_skipLevel--;
+ else
+ m_skipLevel++;
+ if ((ret == ReturnTrue || ret == ReturnFalse) && blockLen)
+ ret = visitProBlock(tokPtr);
+ if (okey)
+ m_skipLevel--;
+ } else {
+ if (okey)
+ ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
+ tokPtr += blockLen;
+ blockLen = getBlockLen(tokPtr);
+ if (!okey)
+ ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
+ }
+ tokPtr += blockLen;
+ okey = true, or_op = false; // force next evaluation
+ break;
+ case TokForLoop:
+ if (m_cumulative) { // This is a no-win situation, so just pretend it's no loop
+ skipHashStr(tokPtr);
+ uint exprLen = getBlockLen(tokPtr);
+ tokPtr += exprLen;
+ blockLen = getBlockLen(tokPtr);
+ ret = visitProBlock(tokPtr);
+ } else if (okey != or_op) {
+ const ProString &variable = getHashStr(tokPtr);
+ uint exprLen = getBlockLen(tokPtr);
+ const ushort *exprPtr = tokPtr;
+ tokPtr += exprLen;
+ blockLen = getBlockLen(tokPtr);
+ ret = visitProLoop(variable, exprPtr, tokPtr);
+ } else {
+ skipHashStr(tokPtr);
+ uint exprLen = getBlockLen(tokPtr);
+ tokPtr += exprLen;
+ blockLen = getBlockLen(tokPtr);
+ ret = ReturnTrue;
+ }
+ tokPtr += blockLen;
+ okey = true, or_op = false; // force next evaluation
+ break;
+ case TokTestDef:
+ case TokReplaceDef:
+ if (m_cumulative || okey != or_op) {
+ const ProString &name = getHashStr(tokPtr);
+ blockLen = getBlockLen(tokPtr);
+ visitProFunctionDef(tok, name, tokPtr);
+ } else {
+ skipHashStr(tokPtr);
+ blockLen = getBlockLen(tokPtr);
+ }
+ tokPtr += blockLen;
+ okey = true, or_op = false; // force next evaluation
+ continue;
+ case TokNot:
+ invert ^= true;
+ continue;
+ case TokAnd:
+ or_op = false;
+ continue;
+ case TokOr:
+ or_op = true;
+ continue;
+ case TokCondition:
+ if (!m_skipLevel && okey != or_op) {
+ if (curr.size() != 1) {
+ logMessage(format("Conditional must expand to exactly one word."));
+ okey = false;
+ } else {
+ okey = isActiveConfig(curr.at(0).toQString(m_tmp2), true) ^ invert;
+ }
+ }
+ or_op = !okey; // tentatively force next evaluation
+ invert = false;
+ curr.clear();
+ continue;
+ case TokTestCall:
+ if (!m_skipLevel && okey != or_op) {
+ if (curr.size() != 1) {
+ logMessage(format("Test name must expand to exactly one word."));
+ skipExpression(tokPtr);
+ okey = false;
+ } else {
+ ret = evaluateConditionalFunction(curr.at(0), tokPtr);
+ switch (ret) {
+ case ReturnTrue: okey = true; break;
+ case ReturnFalse: okey = false; break;
+ default: return ret;
+ }
+ okey ^= invert;
+ }
+ } else if (m_cumulative) {
+ m_skipLevel++;
+ if (curr.size() != 1)
+ skipExpression(tokPtr);
+ else
+ evaluateConditionalFunction(curr.at(0), tokPtr);
+ m_skipLevel--;
+ } else {
+ skipExpression(tokPtr);
+ }
+ or_op = !okey; // tentatively force next evaluation
+ invert = false;
+ curr.clear();
+ continue;
+ default: {
+ const ushort *oTokPtr = --tokPtr;
+ evaluateExpression(tokPtr, &curr, false);
+ if (tokPtr != oTokPtr)
+ continue;
+ }
+ Q_ASSERT_X(false, "visitProBlock", "unexpected item type");
}
+ if (ret != ReturnTrue && ret != ReturnFalse)
+ break;
}
- return rt;
+ return ret;
}
-ProItem::ProItemReturn ProFileEvaluator::Private::visitProLoopIteration()
+
+void ProFileEvaluator::Private::visitProFunctionDef(
+ ushort tok, const ProString &name, const ushort *tokPtr)
{
- ProLoop &loop = m_loopStack.top();
+ QHash<ProString, FunctionDef> *hash =
+ (tok == TokTestDef
+ ? &m_functionDefs.testFunctions
+ : &m_functionDefs.replaceFunctions);
+ FunctionDef def;
+ def.string = m_stringStack.top();
+ def.offset = tokPtr - (const ushort *)def.string.constData();
+ hash->insert(name, def);
+}
- if (loop.infinite) {
- if (!loop.variable.isEmpty())
- m_valuemapStack.top()[loop.variable] = QStringList(QString::number(loop.index++));
- if (loop.index > 1000) {
- errorMessage(format("ran into infinite loop (> 1000 iterations)."));
- return ProItem::ReturnFalse;
+ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::visitProLoop(
+ const ProString &_variable, const ushort *exprPtr, const ushort *tokPtr)
+{
+ VisitReturn ret = ReturnTrue;
+ bool infinite = false;
+ int index = 0;
+ ProString variable;
+ ProStringList oldVarVal;
+ ProString it_list = expandVariableReferences(exprPtr, 0, true).at(0);
+ if (_variable.isEmpty()) {
+ if (it_list != statics.strever) {
+ logMessage(format("Invalid loop expression."));
+ return ReturnFalse;
}
+ it_list = ProString(statics.strforever);
} else {
- QString val;
- do {
- if (loop.index >= loop.list.count())
- return ProItem::ReturnFalse;
- val = loop.list.at(loop.index++);
- } while (val.isEmpty()); // stupid, but qmake is like that
- m_valuemapStack.top()[loop.variable] = QStringList(val);
+ variable = map(_variable);
+ oldVarVal = valuesDirect(variable);
+ }
+ ProStringList list = valuesDirect(it_list);
+ if (list.isEmpty()) {
+ if (it_list == statics.strforever) {
+ infinite = true;
+ } else {
+ const QString &itl = it_list.toQString(m_tmp1);
+ int dotdot = itl.indexOf(statics.strDotDot);
+ if (dotdot != -1) {
+ bool ok;
+ int start = itl.left(dotdot).toInt(&ok);
+ if (ok) {
+ int end = itl.mid(dotdot+2).toInt(&ok);
+ if (ok) {
+ if (start < end) {
+ for (int i = start; i <= end; i++)
+ list << ProString(QString::number(i), NoHash);
+ } else {
+ for (int i = start; i >= end; i--)
+ list << ProString(QString::number(i), NoHash);
+ }
+ }
+ }
+ }
+ }
}
- return ProItem::ReturnTrue;
-}
-void ProFileEvaluator::Private::visitProLoopCleanup()
-{
- ProLoop &loop = m_loopStack.top();
- m_valuemapStack.top()[loop.variable] = loop.oldVarVal;
- m_loopStack.pop_back();
+ m_loopLevel++;
+ forever {
+ if (infinite) {
+ if (!variable.isEmpty())
+ m_valuemapStack.top()[variable] = ProStringList(ProString(QString::number(index++), NoHash));
+ if (index > 1000) {
+ errorMessage(format("ran into infinite loop (> 1000 iterations)."));
+ break;
+ }
+ } else {
+ ProString val;
+ do {
+ if (index >= list.count())
+ goto do_break;
+ val = list.at(index++);
+ } while (val.isEmpty()); // stupid, but qmake is like that
+ m_valuemapStack.top()[variable] = ProStringList(val);
+ }
+
+ ret = visitProBlock(tokPtr);
+ switch (ret) {
+ case ReturnTrue:
+ case ReturnFalse:
+ break;
+ case ReturnNext:
+ ret = ReturnTrue;
+ break;
+ case ReturnBreak:
+ ret = ReturnTrue;
+ goto do_break;
+ default:
+ goto do_break;
+ }
+ }
+ do_break:
+ m_loopLevel--;
+
+ if (!variable.isEmpty())
+ m_valuemapStack.top()[variable] = oldVarVal;
+ return ret;
}
-void ProFileEvaluator::Private::visitProVariable(ProVariable *var)
+void ProFileEvaluator::Private::visitProVariable(
+ ushort tok, const ProStringList &curr, const ushort *&tokPtr)
{
- m_lineNo = var->lineNumber();
- const QString &varName = var->variable();
+ int sizeHint = *tokPtr++;
+
+ if (curr.size() != 1) {
+ skipExpression(tokPtr);
+ logMessage(format("Left hand side of assignment must expand to exactly one word."));
+ return;
+ }
+ const ProString &varName = map(curr.first());
- if (var->variableOperator() == ProVariable::ReplaceOperator) { // ~=
+ if (tok == TokReplace) { // ~=
// DEFINES ~= s/a/b/?[gqi]
- QString val = var->value();
- doVariableReplace(&val);
+ const ProStringList &varVal = expandVariableReferences(tokPtr, sizeHint, true);
+ const QString &val = varVal.at(0).toQString(m_tmp1);
if (val.length() < 4 || val.at(0) != QLatin1Char('s')) {
logMessage(format("the ~= operator can handle only the s/// function."));
return;
if (!m_skipLevel || m_cumulative) {
// We could make a union of modified and unmodified values,
// but this will break just as much as it fixes, so leave it as is.
- replaceInList(&valuesRef(varName), regexp, replace, global);
- replaceInList(&m_filevaluemap[currentProFile()][varName], regexp, replace, global);
+ replaceInList(&valuesRef(varName), regexp, replace, global, m_tmp2);
+ replaceInList(&m_filevaluemap[currentProFile()][varName], regexp, replace, global, m_tmp2);
}
} else {
- bool doSemicolon = (varName == statics.deppath || varName == statics.incpath);
- QStringList varVal = expandVariableReferences(var->value(), doSemicolon);
-
- switch (var->variableOperator()) {
- default: // ReplaceOperator - cannot happen
- case ProVariable::SetOperator: // =
+ ProStringList varVal = expandVariableReferences(tokPtr, sizeHint);
+ switch (tok) {
+ default: // whatever - cannot happen
+ case TokAssign: // =
if (!m_cumulative) {
if (!m_skipLevel) {
+ zipEmpty(&varVal);
m_valuemapStack.top()[varName] = varVal;
m_filevaluemap[currentProFile()][varName] = varVal;
}
} else {
// We are greedy for values.
+ zipEmpty(&varVal);
valuesRef(varName) += varVal;
m_filevaluemap[currentProFile()][varName] += varVal;
}
break;
- case ProVariable::UniqueAddOperator: // *=
+ case TokAppendUnique: // *=
if (!m_skipLevel || m_cumulative) {
insertUnique(&valuesRef(varName), varVal);
insertUnique(&m_filevaluemap[currentProFile()][varName], varVal);
}
break;
- case ProVariable::AddOperator: // +=
+ case TokAppend: // +=
if (!m_skipLevel || m_cumulative) {
+ zipEmpty(&varVal);
valuesRef(varName) += varVal;
m_filevaluemap[currentProFile()][varName] += varVal;
}
break;
- case ProVariable::RemoveOperator: // -=
+ case TokRemove: // -=
if (!m_cumulative) {
if (!m_skipLevel) {
removeEach(&valuesRef(varName), varVal);
}
}
-void ProFileEvaluator::Private::visitProOperator(ProOperator *oper)
-{
- m_invertNext = (oper->operatorKind() == ProOperator::NotOperator);
-}
-
-void ProFileEvaluator::Private::visitProCondition(ProCondition *cond)
-{
- if (!m_skipLevel) {
- m_hadCondition = true;
- if (!cond->text().compare(statics.strelse, Qt::CaseInsensitive)) {
- m_sts.condition = !m_sts.prevCondition;
- } else {
- m_sts.prevCondition = false;
- if (!m_sts.condition && isActiveConfig(cond->text(), true) ^ m_invertNext)
- m_sts.condition = true;
- }
- }
- m_invertNext = false;
-}
-
-ProItem::ProItemReturn ProFileEvaluator::Private::visitProFile(ProFile *pro)
+ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::visitProFile(ProFile *pro)
{
- m_lineNo = pro->lineNumber();
-
+ m_lineNo = 0;
m_profileStack.push(pro);
if (m_profileStack.count() == 1) {
// Do this only for the initial profile we visit, since
}
if (!qmake_cache.isEmpty()) {
qmake_cache = resolvePath(qmake_cache);
- QHash<QString, QStringList> cache_valuemap;
+ QHash<ProString, ProStringList> cache_valuemap;
if (evaluateFileInto(qmake_cache, &cache_valuemap, 0)) {
if (m_option->qmakespec.isEmpty()) {
- const QStringList &vals = cache_valuemap.value(QLatin1String("QMAKESPEC"));
+ const ProStringList &vals = cache_valuemap.value(ProString("QMAKESPEC"));
if (!vals.isEmpty())
- m_option->qmakespec = vals.first();
+ m_option->qmakespec = vals.first().toQString();
}
} else {
qmake_cache.clear();
// We can't resolve symlinks as they do on Unix, so configure.exe puts
// the source of the qmake.conf at the end of the default/qmake.conf in
// the QMAKESPEC_ORG variable.
- const QStringList &spec_org =
- m_option->base_valuemap.value(QLatin1String("QMAKESPEC_ORIGINAL"));
+ const ProStringList &spec_org =
+ m_option->base_valuemap.value(ProString("QMAKESPEC_ORIGINAL"));
if (!spec_org.isEmpty())
m_option->qmakespec_name =
- IoUtils::fileName(spec_org.first()).toString();
+ IoUtils::fileName(spec_org.first().toQString()).toString();
#endif
}
}
#endif
m_valuemapStack.top() = m_option->base_valuemap;
-
- clearFunctions(&m_functionDefs);
m_functionDefs = m_option->base_functions;
- refFunctions(&m_functionDefs.testFunctions);
- refFunctions(&m_functionDefs.replaceFunctions);
- QStringList &tgt = m_valuemapStack.top()[QLatin1String("TARGET")];
+ ProStringList &tgt = m_valuemapStack.top()[ProString("TARGET")];
if (tgt.isEmpty())
- tgt.append(QFileInfo(pro->fileName()).baseName());
+ tgt.append(ProString(QFileInfo(pro->fileName()).baseName(), NoHash));
- QStringList &tmp = m_valuemapStack.top()[QLatin1String("CONFIG")];
- tmp.append(m_addUserConfigCmdArgs);
+ ProStringList &tmp = m_valuemapStack.top()[ProString("CONFIG")];
+ foreach (const QString &add, m_addUserConfigCmdArgs)
+ tmp.append(ProString(add, NoHash));
foreach (const QString &remove, m_removeUserConfigCmdArgs)
- tmp.removeAll(remove);
+ removeAll(&tmp, ProString(remove, NoHash));
}
}
- visitProBlock(pro);
-
- m_lineNo = pro->lineNumber();
+ m_stringStack.push(pro->items());
+ visitProBlock((const ushort *)pro->items().constData());
+ m_stringStack.pop();
if (m_profileStack.count() == 1) {
if (m_parsePreAndPostFiles) {
QSet<QString> processed;
forever {
bool finished = true;
- QStringList configs = valuesDirect(statics.strCONFIG);
+ ProStringList configs = valuesDirect(statics.strCONFIG);
for (int i = configs.size() - 1; i >= 0; --i) {
- const QString config = configs.at(i).toLower();
+ QString config = configs.at(i).toQString(m_tmp1).toLower();
if (!processed.contains(config)) {
+ config.detach();
processed.insert(config);
if (evaluateFeatureFile(config)) {
finished = false;
}
m_profileStack.pop();
- return ProItem::ReturnTrue;
-}
-
-ProItem::ProItemReturn ProFileEvaluator::Private::visitProFunction(ProFunction *func)
-{
- // Make sure that called subblocks don't inherit & destroy the state
- bool invertThis = m_invertNext;
- m_invertNext = false;
- if (!m_skipLevel) {
- m_hadCondition = true;
- m_sts.prevCondition = false;
- }
- if (m_cumulative || !m_sts.condition) {
- QString text = func->text();
- int lparen = text.indexOf(QLatin1Char('('));
- int rparen = text.lastIndexOf(QLatin1Char(')'));
- Q_ASSERT(lparen < rparen);
- QString arguments = text.mid(lparen + 1, rparen - lparen - 1);
- QString funcName = text.left(lparen);
- m_lineNo = func->lineNumber();
- ProItem::ProItemReturn result = evaluateConditionalFunction(funcName.trimmed(), arguments);
- if (result != ProItem::ReturnFalse && result != ProItem::ReturnTrue)
- return result;
- if (!m_skipLevel && ((result == ProItem::ReturnTrue) ^ invertThis))
- m_sts.condition = true;
- }
- return ProItem::ReturnTrue;
+ return ReturnTrue;
}
return cur->directoryName();
}
-void ProFileEvaluator::Private::doVariableReplace(QString *str)
-{
- *str = expandVariableReferences(*str).join(statics.field_sep);
-}
-
-// Be fast even for debug builds
-#ifdef __GNUC__
-# define ALWAYS_INLINE __attribute__((always_inline))
-#else
-# define ALWAYS_INLINE
-#endif
-
// The (QChar*)current->constData() constructs below avoid pointless detach() calls
-static inline void ALWAYS_INLINE appendChar(ushort unicode,
- QString *current, QChar **ptr, QString *pending)
+// FIXME: This is inefficient. Should not make new string if it is a straight subsegment
+static ALWAYS_INLINE void appendChar(ushort unicode,
+ QString *current, QChar **ptr, ProString *pending)
{
if (!pending->isEmpty()) {
int len = pending->size();
*(*ptr)++ = QChar(unicode);
}
-static void appendString(const QString &string,
- QString *current, QChar **ptr, QString *pending)
+static void appendString(const ProString &string,
+ QString *current, QChar **ptr, ProString *pending)
{
if (string.isEmpty())
return;
return;
}
*ptr = (QChar*)current->constData() + len;
- ::memcpy(*ptr, string.data(), string.size() * 2);
+ ::memcpy(*ptr, string.constData(), string.size() * 2);
*ptr += string.size();
}
-static void flushCurrent(QStringList *ret,
- QString *current, QChar **ptr, QString *pending)
+static void flushCurrent(ProStringList *ret,
+ QString *current, QChar **ptr, ProString *pending, bool joined)
{
QChar *uc = (QChar*)current->constData();
int len = *ptr - uc;
if (len) {
- ret->append(QString(uc, len));
+ ret->append(ProString(QString(uc, len), NoHash));
*ptr = uc;
} else if (!pending->isEmpty()) {
ret->append(*pending);
pending->clear();
+ } else if (joined) {
+ ret->append(ProString());
}
}
-static inline void flushFinal(QStringList *ret,
- const QString ¤t, const QChar *ptr, const QString &pending,
- const QString &str, bool replaced)
+static inline void flushFinal(ProStringList *ret,
+ const QString ¤t, const QChar *ptr, const ProString &pending,
+ const ProString &str, bool replaced, bool joined)
{
int len = ptr - current.data();
if (len) {
if (!replaced && len == str.size())
ret->append(str);
else
- ret->append(QString(current.data(), len));
+ ret->append(ProString(QString(current.data(), len), NoHash));
} else if (!pending.isEmpty()) {
ret->append(pending);
+ } else if (joined) {
+ ret->append(ProString());
}
}
-QStringList ProFileEvaluator::Private::expandVariableReferences(
- const QString &str, bool do_semicolon, int *pos)
+ProStringList ProFileEvaluator::Private::expandVariableReferences(
+ const ProString &str, int *pos, bool joined)
{
- QStringList ret;
+ ProStringList ret;
// if (ok)
// *ok = true;
- if (str.isEmpty())
+ if (str.isEmpty() && !pos)
return ret;
const ushort LSQUARE = '[';
const ushort DOT = '.';
const ushort SPACE = ' ';
const ushort TAB = '\t';
- const ushort SEMICOLON = ';';
const ushort COMMA = ',';
const ushort SINGLEQUOTE = '\'';
const ushort DOUBLEQUOTE = '"';
ushort unicode, quote = 0, parens = 0;
- const ushort *str_data = (const ushort *)str.data();
- const int str_len = str.length();
+ const ushort *str_data = (const ushort *)str.constData();
+ const int str_len = str.size();
- QString var, args;
+ ProString var, args;
bool replaced = false;
+ bool putSpace = false;
QString current; // Buffer for successively assembled string segments
current.resize(str.size());
QChar *ptr = current.data();
- QString pending; // Buffer for string segments from variables
+ ProString pending; // Buffer for string segments from variables
// Only one of the above buffers can be filled at a given time.
for (int i = pos ? *pos : 0; i < str_len; ++i) {
unicode = str_data[i];
unicode = str_data[i];
// at this point, i points to either the 'term' or 'next' character (which is in unicode)
}
- var = QString::fromRawData((QChar*)str_data + name_start, i - name_start);
+ var = str.mid(name_start, i - name_start);
if (var_type == VAR && unicode == LPAREN) {
var_type = FUNCTION;
name_start = i + 1;
--depth;
}
}
- args = QString((QChar*)str_data + name_start, i - name_start);
+ args = str.mid(name_start, i - name_start);
if (++i < str_len)
unicode = str_data[i];
else
// *ok = false;
if (pos)
*pos = str_len;
- return QStringList();
+ return ProStringList();
}
} else {
// move the 'cursor' back to the last char of the thing we were looking at
--i;
}
- QStringList replacement;
+ ProStringList replacement;
if (var_type == ENVIRON) {
- replacement = split_value_list(QString::fromLocal8Bit(qgetenv(var.toLocal8Bit().constData())));
+ replacement = split_value_list(QString::fromLocal8Bit(qgetenv(
+ var.toQString(m_tmp1).toLocal8Bit().constData())));
} else if (var_type == PROPERTY) {
- replacement << propertyValue(var);
+ replacement << ProString(propertyValue(var.toQString(m_tmp1)), NoHash);
} else if (var_type == FUNCTION) {
- replacement << evaluateExpandFunction(var, args);
+ replacement += evaluateExpandFunction(var, args);
} else if (var_type == VAR) {
replacement = values(map(var));
}
if (!replacement.isEmpty()) {
- if (quote) {
- appendString(replacement.join(statics.field_sep),
+ if (quote || joined) {
+ if (putSpace) {
+ putSpace = false;
+ if (!replacement.at(0).isEmpty()) // Bizarre, indeed
+ appendChar(' ', ¤t, &ptr, &pending);
+ }
+ appendString(ProString(replacement.join(statics.field_sep), NoHash),
¤t, &ptr, &pending);
} else {
appendString(replacement.at(0), ¤t, &ptr, &pending);
if (replacement.size() > 1) {
- flushCurrent(&ret, ¤t, &ptr, &pending);
+ flushCurrent(&ret, ¤t, &ptr, &pending, false);
int j = 1;
if (replacement.size() > 2) {
// FIXME: ret.reserve(ret.size() + replacement.size() - 2);
if (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE) {
quote = unicode;
continue;
- } else if ((do_semicolon && unicode == SEMICOLON) ||
- unicode == SPACE || unicode == TAB) {
- flushCurrent(&ret, ¤t, &ptr, &pending);
+ } else if (unicode == SPACE || unicode == TAB) {
+ if (!joined)
+ flushCurrent(&ret, ¤t, &ptr, &pending, false);
+ else if ((ptr - (QChar*)current.constData()) || !pending.isEmpty())
+ putSpace = true;
continue;
} else if (pos) {
if (unicode == LPAREN) {
} else if (unicode == RPAREN) {
--parens;
} else if (!parens && unicode == COMMA) {
- *pos = i + 1;
- flushFinal(&ret, current, ptr, pending, str, replaced);
- return ret;
+ if (!joined) {
+ *pos = i + 1;
+ flushFinal(&ret, current, ptr, pending, str, replaced, false);
+ return ret;
+ }
+ flushCurrent(&ret, ¤t, &ptr, &pending, true);
+ putSpace = false;
+ continue;
}
}
}
+ if (putSpace) {
+ putSpace = false;
+ appendChar(' ', ¤t, &ptr, &pending);
+ }
appendChar(unicode, ¤t, &ptr, &pending);
}
if (pos)
*pos = str_len;
- flushFinal(&ret, current, ptr, pending, str, replaced);
+ flushFinal(&ret, current, ptr, pending, str, replaced, joined);
return ret;
}
return true;
if (regex && (config.contains(QLatin1Char('*')) || config.contains(QLatin1Char('?')))) {
- QRegExp re(config, Qt::CaseSensitive, QRegExp::Wildcard);
+ QString cfg = config;
+ cfg.detach(); // Keep m_tmp out of QRegExp's cache
+ QRegExp re(cfg, Qt::CaseSensitive, QRegExp::Wildcard);
if (re.exactMatch(m_option->qmakespec_name))
return true;
// CONFIG variable
- foreach (const QString &configValue, valuesDirect(statics.strCONFIG)) {
- if (re.exactMatch(configValue))
+ int t = 0;
+ foreach (const ProString &configValue, valuesDirect(statics.strCONFIG)) {
+ if (re.exactMatch(configValue.toQString(m_tmp[t])))
return true;
+ t ^= 1;
}
} else {
// mkspecs
return true;
// CONFIG variable
- foreach (const QString &configValue, valuesDirect(statics.strCONFIG)) {
- if (configValue == config)
- return true;
- }
+ if (valuesDirect(statics.strCONFIG).contains(ProString(config, NoHash)))
+ return true;
}
return false;
}
-QList<QStringList> ProFileEvaluator::Private::prepareFunctionArgs(const QString &arguments)
+ProStringList ProFileEvaluator::Private::expandVariableReferences(
+ const ushort *&tokPtr, int sizeHint, bool joined)
+{
+ ProStringList ret;
+ ret.reserve(sizeHint);
+ forever {
+ evaluateExpression(tokPtr, &ret, joined);
+ switch (*tokPtr) {
+ case TokValueTerminator:
+ case TokFuncTerminator:
+ tokPtr++;
+ return ret;
+ case TokArgSeparator:
+ if (joined) {
+ tokPtr++;
+ continue;
+ }
+ // fallthrough
+ default:
+ Q_ASSERT_X(false, "expandVariableReferences", "Unrecognized token");
+ break;
+ }
+ }
+}
+
+QList<ProStringList> ProFileEvaluator::Private::prepareFunctionArgs(const ushort *&tokPtr)
+{
+ QList<ProStringList> args_list;
+ if (*tokPtr != TokFuncTerminator) {
+ for (;; tokPtr++) {
+ ProStringList arg;
+ evaluateExpression(tokPtr, &arg, false);
+ args_list << arg;
+ if (*tokPtr == TokFuncTerminator)
+ break;
+ Q_ASSERT(*tokPtr == TokArgSeparator);
+ }
+ }
+ tokPtr++;
+ return args_list;
+}
+
+QList<ProStringList> ProFileEvaluator::Private::prepareFunctionArgs(const ProString &arguments)
{
- QList<QStringList> args_list;
- for (int pos = 0; pos < arguments.length(); )
- args_list << expandVariableReferences(arguments, false, &pos);
+ QList<ProStringList> args_list;
+ for (int pos = 0; pos < arguments.size(); )
+ args_list << expandVariableReferences(arguments, &pos);
return args_list;
}
-QStringList ProFileEvaluator::Private::evaluateFunction(
- ProBlock *funcPtr, const QList<QStringList> &argumentsList, bool *ok)
+ProStringList ProFileEvaluator::Private::evaluateFunction(
+ const FunctionDef &func, const QList<ProStringList> &argumentsList, bool *ok)
{
bool oki;
- QStringList ret;
+ ProStringList ret;
+ const ushort *tokPtr = (const ushort *)func.string.constData() + func.offset;
if (m_valuemapStack.count() >= 100) {
errorMessage(format("ran into infinite recursion (depth > 100)."));
oki = false;
} else {
- State sts = m_sts;
- m_valuemapStack.push(QHash<QString, QStringList>());
+ m_valuemapStack.push(QHash<ProString, ProStringList>());
+ m_stringStack.push(func.string);
+ int loopLevel = m_loopLevel;
+ m_loopLevel = 0;
- QStringList args;
+ ProStringList args;
for (int i = 0; i < argumentsList.count(); ++i) {
args += argumentsList[i];
- m_valuemapStack.top()[QString::number(i+1)] = argumentsList[i];
+ m_valuemapStack.top()[ProString(QString::number(i+1))] = argumentsList[i];
}
m_valuemapStack.top()[statics.strARGS] = args;
- oki = (visitProBlock(funcPtr) != ProItem::ReturnFalse); // True || Return
+ oki = (visitProBlock(tokPtr) != ReturnFalse); // True || Return
ret = m_returnValue;
m_returnValue.clear();
+ m_loopLevel = loopLevel;
+ m_stringStack.pop();
m_valuemapStack.pop();
- m_sts = sts;
}
if (ok)
*ok = oki;
if (oki)
return ret;
- return QStringList();
+ return ProStringList();
}
-QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &func, const QString &arguments)
+ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateBoolFunction(
+ const FunctionDef &func, const QList<ProStringList> &argumentsList,
+ const ProString &function)
{
- QList<QStringList> args_list = prepareFunctionArgs(arguments);
+ bool ok;
+ ProStringList ret = evaluateFunction(func, argumentsList, &ok);
+ if (ok) {
+ if (ret.isEmpty())
+ return ReturnTrue;
+ if (ret.at(0) != statics.strfalse) {
+ if (ret.at(0) == statics.strtrue)
+ return ReturnTrue;
+ int val = ret.at(0).toQString(m_tmp1).toInt(&ok);
+ if (ok) {
+ if (val)
+ return ReturnTrue;
+ } else {
+ logMessage(format("Unexpected return value from test '%1': %2")
+ .arg(function.toQString(m_tmp1))
+ .arg(ret.join(QLatin1String(" :: "))));
+ }
+ }
+ }
+ return ReturnFalse;
+}
- if (ProBlock *funcPtr = m_functionDefs.replaceFunctions.value(func, 0))
- return evaluateFunction(funcPtr, args_list, 0);
+ProStringList ProFileEvaluator::Private::evaluateExpandFunction(
+ const ProString &func, const ushort *&tokPtr)
+{
+ QHash<ProString, FunctionDef>::ConstIterator it =
+ m_functionDefs.replaceFunctions.constFind(func);
+ if (it != m_functionDefs.replaceFunctions.constEnd())
+ return evaluateFunction(*it, prepareFunctionArgs(tokPtr), 0);
- QStringList args; //why don't the builtin functions just use args_list? --Sam
- foreach (const QStringList &arg, args_list)
- args += arg.join(statics.field_sep);
+ //why don't the builtin functions just use args_list? --Sam
+ return evaluateExpandFunction(func, expandVariableReferences(tokPtr, 5, true));
+}
- ExpandFunc func_t = ExpandFunc(statics.expands.value(func.toLower()));
+ProStringList ProFileEvaluator::Private::evaluateExpandFunction(
+ const ProString &func, const ProString &arguments)
+{
+ QHash<ProString, FunctionDef>::ConstIterator it =
+ m_functionDefs.replaceFunctions.constFind(func);
+ if (it != m_functionDefs.replaceFunctions.constEnd())
+ return evaluateFunction(*it, prepareFunctionArgs(arguments), 0);
+
+ //why don't the builtin functions just use args_list? --Sam
+ int pos = 0;
+ return evaluateExpandFunction(func, expandVariableReferences(arguments, &pos, true));
+}
- QStringList ret;
+ProStringList ProFileEvaluator::Private::evaluateExpandFunction(
+ const ProString &func, const ProStringList &args)
+{
+ ExpandFunc func_t = ExpandFunc(statics.expands.value(func.toQString(m_tmp1).toLower()));
+
+ ProStringList ret;
switch (func_t) {
case E_BASENAME:
case E_DIRNAME:
case E_SECTION: {
bool regexp = false;
- QString sep, var;
+ QString sep;
+ ProString var;
int beg = 0;
int end = -1;
if (func_t == E_SECTION) {
if (args.count() != 3 && args.count() != 4) {
logMessage(format("%1(var) section(var, sep, begin, end) "
- "requires three or four arguments.").arg(func));
+ "requires three or four arguments.").arg(func.toQString(m_tmp1)));
} else {
var = args[0];
- sep = args[1];
- beg = args[2].toInt();
+ sep = args.at(1).toQString();
+ beg = args.at(2).toQString(m_tmp2).toInt();
if (args.count() == 4)
- end = args[3].toInt();
+ end = args.at(3).toQString(m_tmp2).toInt();
}
} else {
if (args.count() != 1) {
- logMessage(format("%1(var) requires one argument.").arg(func));
+ logMessage(format("%1(var) requires one argument.")
+ .arg(func.toQString(m_tmp1)));
} else {
var = args[0];
regexp = true;
beg = -1;
}
}
- if (!var.isNull()) {
+ if (!var.isEmpty()) {
if (regexp) {
QRegExp sepRx(sep);
- foreach (const QString &str, values(map(var)))
- ret += str.section(sepRx, beg, end);
+ foreach (const ProString &str, values(map(var))) {
+ const QString &rstr = str.toQString(m_tmp1).section(sepRx, beg, end);
+ ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr, NoHash));
+ }
} else {
- foreach (const QString &str, values(map(var)))
- ret += str.section(sep, beg, end);
+ foreach (const ProString &str, values(map(var))) {
+ const QString &rstr = str.toQString(m_tmp1).section(sep, beg, end);
+ ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr, NoHash));
+ }
}
}
break;
if(args.count() < 1) {
logMessage(format("sprintf(format, ...) requires at least one argument"));
} else {
- QString tmp = args.at(0);
+ QString tmp = args.at(0).toQString(m_tmp1);
for (int i = 1; i < args.count(); ++i)
- tmp = tmp.arg(args.at(i));
+ tmp = tmp.arg(args.at(i).toQString(m_tmp2));
+ // Note: this depends on split_value_list() making a deep copy
ret = split_value_list(tmp);
}
break;
if (args.count() < 1 || args.count() > 4) {
logMessage(format("join(var, glue, before, after) requires one to four arguments."));
} else {
- QString glue, before, after;
+ QString glue;
+ ProString before, after;
if (args.count() >= 2)
- glue = args[1];
+ glue = args.at(1).toQString(m_tmp1);
if (args.count() >= 3)
before = args[2];
if (args.count() == 4)
after = args[3];
- const QStringList &var = values(map(args.first()));
+ const ProStringList &var = values(map(args.at(0)));
if (!var.isEmpty())
- ret.append(before + var.join(glue) + after);
+ ret.append(ProString(before + var.join(glue) + after, NoHash));
}
break;
}
if (args.count() != 2) {
logMessage(format("split(var, sep) requires one or two arguments"));
} else {
- const QString &sep = (args.count() == 2) ? args[1] : statics.field_sep;
- foreach (const QString &var, values(map(args.first())))
- foreach (const QString &splt, var.split(sep))
- ret.append(splt);
+ const QString &sep = (args.count() == 2) ? args.at(1).toQString(m_tmp1) : statics.field_sep;
+ foreach (const ProString &var, values(map(args.at(0))))
+ foreach (const QString &splt, var.toQString(m_tmp2).split(sep))
+ ret << (splt.isSharedWith(m_tmp2) ? var : ProString(splt, NoHash));
}
break;
case E_MEMBER:
logMessage(format("member(var, start, end) requires one to three arguments."));
} else {
bool ok = true;
- const QStringList &var = values(map(args.first()));
+ const ProStringList &var = values(map(args.at(0)));
int start = 0, end = 0;
if (args.count() >= 2) {
- QString start_str = args[1];
+ const QString &start_str = args.at(1).toQString(m_tmp1);
start = start_str.toInt(&ok);
if (!ok) {
if (args.count() == 2) {
} else {
end = start;
if (args.count() == 3)
- end = args[2].toInt(&ok);
+ end = args.at(2).toQString(m_tmp1).toInt(&ok);
if (!ok)
logMessage(format("member() argument 3 (end) '%2' invalid.\n")
- .arg(args[2]));
+ .arg(args.at(2).toQString(m_tmp1)));
}
}
if (ok) {
case E_FIRST:
case E_LAST:
if (args.count() != 1) {
- logMessage(format("%1(var) requires one argument.").arg(func));
+ logMessage(format("%1(var) requires one argument.").arg(func.toQString(m_tmp1)));
} else {
- const QStringList var = values(map(args.first()));
+ const ProStringList &var = values(map(args.at(0)));
if (!var.isEmpty()) {
if (func_t == E_FIRST)
ret.append(var[0]);
}
}
break;
+ case E_SIZE:
+ if(args.count() != 1)
+ logMessage(format("size(var) requires one argument."));
+ else
+ ret.append(ProString(QString::number(values(map(args.at(0))).size()), NoHash));
+ break;
case E_CAT:
if (args.count() < 1 || args.count() > 2) {
logMessage(format("cat(file, singleline=true) requires one or two arguments."));
} else {
- QString file = args[0];
+ const QString &file = args.at(0).toQString(m_tmp1);
bool singleLine = true;
if (args.count() > 1)
- singleLine = (!args[1].compare(statics.strtrue, Qt::CaseInsensitive));
+ singleLine = isTrue(args.at(1), m_tmp2);
QFile qfile(resolvePath(expandEnvVars(file)));
if (qfile.open(QIODevice::ReadOnly)) {
while (!stream.atEnd()) {
ret += split_value_list(stream.readLine().trimmed());
if (!singleLine)
- ret += QLatin1String("\n");
+ ret += ProString("\n", NoHash);
}
qfile.close();
}
if (args.count() != 2) {
logMessage(format("fromfile(file, variable) requires two arguments."));
} else {
- QHash<QString, QStringList> vars;
- if (evaluateFileInto(resolvePath(expandEnvVars(args.at(0))), &vars, 0))
- ret = vars.value(args.at(1));
+ QHash<ProString, ProStringList> vars;
+ if (evaluateFileInto(resolvePath(expandEnvVars(args.at(0).toQString(m_tmp1))), &vars, 0))
+ ret = vars.value(map(args.at(1)));
}
break;
case E_EVAL:
case E_LIST: {
QString tmp;
tmp.sprintf(".QMAKE_INTERNAL_TMP_variableName_%d", m_listCount++);
- ret = QStringList(tmp);
- QStringList lst;
- foreach (const QString &arg, args)
- lst += split_value_list(arg);
- m_valuemapStack.top()[tmp] = lst;
+ ret = ProStringList(ProString(tmp, NoHash));
+ ProStringList lst;
+ foreach (const ProString &arg, args)
+ lst += split_value_list(arg.toQString(m_tmp1)); // Relies on deep copy
+ m_valuemapStack.top()[ret.at(0)] = lst;
break; }
case E_FIND:
if (args.count() != 2) {
logMessage(format("find(var, str) requires two arguments."));
} else {
- QRegExp regx(args[1]);
- foreach (const QString &val, values(map(args.first())))
- if (regx.indexIn(val) != -1)
+ QRegExp regx(args.at(1).toQString());
+ int t = 0;
+ foreach (const ProString &val, values(map(args.at(0)))) {
+ if (regx.indexIn(val.toQString(m_tmp[t])) != -1)
ret += val;
+ t ^= 1;
+ }
}
break;
case E_SYSTEM:
+ QLatin1String(" && ") + args[0]).toLocal8Bit(), "r");
bool singleLine = true;
if (args.count() > 1)
- singleLine = (!args[1].compare(QLatin1String("true"), Qt::CaseInsensitive));
+ singleLine = isTrue(args.at(1), m_tmp2);
QString output;
while (proc && !feof(proc)) {
int read_in = int(fread(buff, 1, 255, proc));
if(args.count() != 1) {
logMessage(format("unique(var) requires one argument."));
} else {
- ret = values(map(args.first()));
+ ret = values(map(args.at(0)));
ret.removeDuplicates();
}
break;
case E_QUOTE:
- for (int i = 0; i < args.count(); ++i)
- ret += QStringList(args.at(i));
+ ret += args;
break;
case E_ESCAPE_EXPAND:
for (int i = 0; i < args.size(); ++i) {
- QChar *i_data = args[i].data();
- int i_len = args[i].length();
+ QString str = args.at(i).toQString();
+ QChar *i_data = str.data();
+ int i_len = str.length();
for (int x = 0; x < i_len; ++x) {
if (*(i_data+x) == QLatin1Char('\\') && x < i_len-1) {
if (*(i_data+x+1) == QLatin1Char('\\')) {
}
}
}
- ret.append(QString(i_data, i_len));
+ ret.append(ProString(QString(i_data, i_len), NoHash));
}
break;
case E_RE_ESCAPE:
- for (int i = 0; i < args.size(); ++i)
- ret += QRegExp::escape(args[i]);
+ for (int i = 0; i < args.size(); ++i) {
+ const QString &rstr = QRegExp::escape(args.at(i).toQString(m_tmp1));
+ ret << (rstr.isSharedWith(m_tmp1) ? args.at(i) : ProString(rstr, NoHash));
+ }
break;
case E_UPPER:
case E_LOWER:
- for (int i = 0; i < args.count(); ++i)
- if (func_t == E_UPPER)
- ret += args[i].toUpper();
- else
- ret += args[i].toLower();
+ for (int i = 0; i < args.count(); ++i) {
+ QString rstr = args.at(i).toQString(m_tmp1);
+ rstr = (func_t == E_UPPER) ? rstr.toUpper() : rstr.toLower();
+ ret << (rstr.isSharedWith(m_tmp1) ? args.at(i) : ProString(rstr, NoHash));
+ }
break;
case E_FILES:
if (args.count() != 1 && args.count() != 2) {
} else {
bool recursive = false;
if (args.count() == 2)
- recursive = (!args[1].compare(statics.strtrue, Qt::CaseInsensitive) || args[1].toInt());
+ recursive = isTrue(args.at(1), m_tmp2);
QStringList dirs;
- QString r = fixPathToLocalOS(args[0]);
+ QString r = fixPathToLocalOS(args.at(0).toQString(m_tmp1));
QString pfx;
if (IoUtils::isRelativePath(r)) {
pfx = currentDirectory();
dirs.append(QString());
}
+ r.detach(); // Keep m_tmp out of QRegExp's cache
const QRegExp regex(r, Qt::CaseSensitive, QRegExp::Wildcard);
for (int d = 0; d < dirs.count(); d++) {
QString dir = dirs[d];
dirs.append(fname + QDir::separator());
}
if (regex.exactMatch(qdir[i]))
- ret += fname;
+ ret += ProString(fname, NoHash);
}
}
}
if(args.count() != 3 ) {
logMessage(format("replace(var, before, after) requires three arguments"));
} else {
- const QRegExp before(args[1]);
- const QString after(args[2]);
- foreach (QString val, values(map(args.first())))
- ret += val.replace(before, after);
+ const QRegExp before(args.at(1).toQString());
+ const QString &after(args.at(2).toQString(m_tmp2));
+ foreach (const ProString &val, values(map(args.at(0)))) {
+ QString rstr = val.toQString(m_tmp1);
+ QString copy = rstr; // Force a detach on modify
+ rstr.replace(before, after);
+ ret << (rstr.isSharedWith(m_tmp1) ? val : ProString(rstr, NoHash));
+ }
}
break;
case 0:
- logMessage(format("'%1' is not a recognized replace function").arg(func));
+ logMessage(format("'%1' is not a recognized replace function")
+ .arg(func.toQString(m_tmp1)));
break;
default:
- logMessage(format("Function '%1' is not implemented").arg(func));
+ logMessage(format("Function '%1' is not implemented").arg(func.toQString(m_tmp1)));
break;
}
return ret;
}
-ProItem::ProItemReturn ProFileEvaluator::Private::evaluateConditionalFunction(
- const QString &function, const QString &arguments)
+ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateConditionalFunction(
+ const ProString &function, const ProString &arguments)
{
- QList<QStringList> args_list = prepareFunctionArgs(arguments);
+ QHash<ProString, FunctionDef>::ConstIterator it =
+ m_functionDefs.testFunctions.constFind(function);
+ if (it != m_functionDefs.testFunctions.constEnd())
+ return evaluateBoolFunction(*it, prepareFunctionArgs(arguments), function);
+
+ //why don't the builtin functions just use args_list? --Sam
+ int pos = 0;
+ return evaluateConditionalFunction(function, expandVariableReferences(arguments, &pos, true));
+}
- if (ProBlock *funcPtr = m_functionDefs.testFunctions.value(function, 0)) {
- bool ok;
- QStringList ret = evaluateFunction(funcPtr, args_list, &ok);
- if (ok) {
- if (ret.isEmpty()) {
- return ProItem::ReturnTrue;
- } else {
- if (ret.first() != statics.strfalse) {
- if (ret.first() == statics.strtrue) {
- return ProItem::ReturnTrue;
- } else {
- bool ok;
- int val = ret.first().toInt(&ok);
- if (ok) {
- if (val)
- return ProItem::ReturnTrue;
- } else {
- logMessage(format("Unexpected return value from test '%1': %2")
- .arg(function).arg(ret.join(QLatin1String(" :: "))));
- }
- }
- }
- }
- }
- return ProItem::ReturnFalse;
- }
+ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateConditionalFunction(
+ const ProString &function, const ushort *&tokPtr)
+{
+ QHash<ProString, FunctionDef>::ConstIterator it =
+ m_functionDefs.testFunctions.constFind(function);
+ if (it != m_functionDefs.testFunctions.constEnd())
+ return evaluateBoolFunction(*it, prepareFunctionArgs(tokPtr), function);
- QStringList args; //why don't the builtin functions just use args_list? --Sam
- foreach (const QStringList &arg, args_list)
- args += arg.join(statics.field_sep);
+ //why don't the builtin functions just use args_list? --Sam
+ return evaluateConditionalFunction(function, expandVariableReferences(tokPtr, 5, true));
+}
+ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateConditionalFunction(
+ const ProString &function, const ProStringList &args)
+{
TestFunc func_t = (TestFunc)statics.functions.value(function);
switch (func_t) {
- case T_DEFINE_TEST:
- m_definingTest = true;
- goto defineFunc;
- case T_DEFINE_REPLACE:
- m_definingTest = false;
- defineFunc:
- if (args.count() != 1) {
- logMessage(format("%s(function) requires one argument.").arg(function));
- return ProItem::ReturnFalse;
- }
- m_definingFunc = args.first();
- return ProItem::ReturnTrue;
case T_DEFINED:
if (args.count() < 1 || args.count() > 2) {
logMessage(format("defined(function, [\"test\"|\"replace\"])"
" requires one or two arguments."));
- return ProItem::ReturnFalse;
+ return ReturnFalse;
}
if (args.count() > 1) {
if (args[1] == QLatin1String("test"))
else if (args[1] == QLatin1String("replace"))
return returnBool(m_functionDefs.replaceFunctions.contains(args[0]));
logMessage(format("defined(function, type):"
- " unexpected type [%1].\n").arg(args[1]));
- return ProItem::ReturnFalse;
+ " unexpected type [%1].\n").arg(args.at(1).toQString(m_tmp1)));
+ return ReturnFalse;
}
return returnBool(m_functionDefs.replaceFunctions.contains(args[0])
|| m_functionDefs.testFunctions.contains(args[0]));
// It is "safe" to ignore returns - due to qmake brokeness
// they cannot be used to terminate loops anyway.
if (m_skipLevel || m_cumulative)
- return ProItem::ReturnTrue;
+ return ReturnTrue;
if (m_valuemapStack.isEmpty()) {
logMessage(format("unexpected return()."));
- return ProItem::ReturnFalse;
+ return ReturnFalse;
}
- return ProItem::ReturnReturn;
+ return ReturnReturn;
case T_EXPORT: {
if (m_skipLevel && !m_cumulative)
- return ProItem::ReturnTrue;
+ return ReturnTrue;
if (args.count() != 1) {
logMessage(format("export(variable) requires one argument."));
- return ProItem::ReturnFalse;
+ return ReturnFalse;
}
- const QString &var = map(args.at(0));
+ const ProString &var = map(args.at(0));
for (int i = m_valuemapStack.size(); --i > 0; ) {
- QHash<QString, QStringList>::Iterator it = m_valuemapStack[i].find(var);
+ QHash<ProString, ProStringList>::Iterator it = m_valuemapStack[i].find(var);
if (it != m_valuemapStack.at(i).end()) {
if (it->constBegin() == statics.fakeValue.constBegin()) {
// This is stupid, but qmake doesn't propagate deletions
- m_valuemapStack[0][var] = QStringList();
+ m_valuemapStack[0][var] = ProStringList();
} else {
m_valuemapStack[0][var] = *it;
}
break;
}
}
- return ProItem::ReturnTrue;
+ return ReturnTrue;
}
case T_INFILE:
if (args.count() < 2 || args.count() > 3) {
logMessage(format("infile(file, var, [values]) requires two or three arguments."));
} else {
- QHash<QString, QStringList> vars;
- if (!evaluateFileInto(resolvePath(expandEnvVars(args.at(0))), &vars, 0))
- return ProItem::ReturnFalse;
+ QHash<ProString, ProStringList> vars;
+ if (!evaluateFileInto(resolvePath(expandEnvVars(args.at(0).toQString(m_tmp1))), &vars, 0))
+ return ReturnFalse;
if (args.count() == 2)
return returnBool(vars.contains(args.at(1)));
QRegExp regx;
- const QString &qry = args.at(2);
- if (qry != QRegExp::escape(qry))
- regx.setPattern(qry);
- foreach (const QString &s, vars.value(args.at(1)))
- if ((!regx.isEmpty() && regx.exactMatch(s)) || s == qry)
- return ProItem::ReturnTrue;
- }
- return ProItem::ReturnFalse;
+ const QString &qry = args.at(2).toQString(m_tmp1);
+ if (qry != QRegExp::escape(qry)) {
+ QString copy = qry;
+ copy.detach();
+ regx.setPattern(copy);
+ }
+ int t = 0;
+ foreach (const ProString &s, vars.value(map(args.at(1)))) {
+ if ((!regx.isEmpty() && regx.exactMatch(s.toQString(m_tmp[t]))) || s == qry)
+ return ReturnTrue;
+ t ^= 1;
+ }
+ }
+ return ReturnFalse;
#if 0
case T_REQUIRES:
#endif
case T_EVAL: {
- ProBlock *pro = new ProBlock();
- QString buf = args.join(statics.field_sep);
- if (!readInternal(pro, buf, (ushort*)buf.data())) {
- delete pro;
- return ProItem::ReturnFalse;
- }
- bool ret = visitProBlock(pro);
- pro->deref();
- return returnBool(ret);
- }
- case T_FOR: {
- if (m_cumulative) // This is a no-win situation, so just pretend it's no loop
- return ProItem::ReturnTrue;
- if (m_skipLevel)
- return ProItem::ReturnFalse;
- if (args.count() > 2 || args.count() < 1) {
- logMessage(format("for({var, list|var, forever|ever})"
- " requires one or two arguments."));
- return ProItem::ReturnFalse;
- }
- ProLoop loop;
- loop.infinite = false;
- loop.index = 0;
- QString it_list;
- if (args.count() == 1) {
- it_list = args[0];
- if (args[0] != statics.strever) {
- logMessage(format("for({var, list|var, forever|ever})"
- " requires one or two arguments."));
- return ProItem::ReturnFalse;
- }
- it_list = statics.strforever;
- } else {
- loop.variable = map(args.at(0));
- loop.oldVarVal = valuesDirect(loop.variable);
- it_list = map(args.at(1));
- }
- loop.list = valuesDirect(it_list);
- if (loop.list.isEmpty()) {
- if (it_list == statics.strforever) {
- loop.infinite = true;
- } else {
- int dotdot = it_list.indexOf(statics.strDotDot);
- if (dotdot != -1) {
- bool ok;
- int start = it_list.left(dotdot).toInt(&ok);
- if (ok) {
- int end = it_list.mid(dotdot+2).toInt(&ok);
- if (ok) {
- if (start < end) {
- for (int i = start; i <= end; i++)
- loop.list << QString::number(i);
- } else {
- for (int i = start; i >= end; i--)
- loop.list << QString::number(i);
- }
- }
- }
- }
- }
+ QString pro;
+ if (!readInternal(&pro, args.join(statics.field_sep)))
+ return ReturnFalse;
+ m_stringStack.push(pro);
+ VisitReturn ret = visitProBlock((const ushort *)pro.constData());
+ m_stringStack.pop();
+ return ret;
}
- m_loopStack.push(loop);
- m_sts.condition = true;
- return ProItem::ReturnLoop;
- }
case T_BREAK:
if (m_skipLevel)
- return ProItem::ReturnFalse;
- if (!m_loopStack.isEmpty())
- return ProItem::ReturnBreak;
- // ### missing: breaking out of multiline blocks
+ return ReturnFalse;
+ if (m_loopLevel)
+ return ReturnBreak;
logMessage(format("unexpected break()."));
- return ProItem::ReturnFalse;
+ return ReturnFalse;
case T_NEXT:
if (m_skipLevel)
- return ProItem::ReturnFalse;
- if (!m_loopStack.isEmpty())
- return ProItem::ReturnNext;
+ return ReturnFalse;
+ if (m_loopLevel)
+ return ReturnNext;
logMessage(format("unexpected next()."));
- return ProItem::ReturnFalse;
+ return ReturnFalse;
case T_IF: {
+ if (m_skipLevel && !m_cumulative)
+ return ReturnFalse;
if (args.count() != 1) {
logMessage(format("if(condition) requires one argument."));
- return ProItem::ReturnFalse;
+ return ReturnFalse;
}
- QString cond = args.first();
- bool escaped = false; // This is more than qmake does
+ const ProString &cond = args.at(0);
bool quoted = false;
bool ret = true;
bool orOp = false;
int parens = 0;
QString test;
test.reserve(20);
- QString args;
- args.reserve(50);
- const QChar *d = cond.unicode();
- const QChar *ed = d + cond.length();
+ QString argsString;
+ argsString.reserve(50);
+ const QChar *d = cond.constData();
+ const QChar *ed = d + cond.size();
while (d < ed) {
ushort c = (d++)->unicode();
- if (!escaped) {
- if (c == '\\') {
- escaped = true;
- args += c; // Assume no-one quotes the test name
- continue;
- } else if (c == '"') {
- quoted = !quoted;
- args += c; // Ditto
- continue;
- }
- } else {
- escaped = false;
- }
+ bool isOp = false;
if (quoted) {
- args += c; // Ditto
+ if (c == '"')
+ quoted = false;
+ else if (c == '!' && test.isEmpty())
+ invert = true;
+ else
+ test += c;
+ } else if (c == '(') {
+ isFunc = true;
+ if (parens)
+ argsString += c;
+ ++parens;
+ } else if (c == ')') {
+ --parens;
+ if (parens)
+ argsString += c;
+ } else if (!parens) {
+ if (c == '"')
+ quoted = true;
+ else if (c == ':' || c == '|')
+ isOp = true;
+ else if (c == '!' && test.isEmpty())
+ invert = true;
+ else
+ test += c;
} else {
- bool isOp = false;
- if (c == '(') {
- isFunc = true;
- if (parens)
- args += c;
- ++parens;
- } else if (c == ')') {
- --parens;
- if (parens)
- args += c;
- } else if (!parens) {
- if (c == ':' || c == '|')
- isOp = true;
- else if (c == '!')
- invert = true;
- else
- test += c;
- } else {
- args += c;
- }
- if (!parens && (isOp || d == ed)) {
- // Yes, qmake doesn't shortcut evaluations here. We can't, either,
- // as some test functions have side effects.
- bool success;
- if (isFunc) {
- success = evaluateConditionalFunction(test, args);
- } else {
- success = isActiveConfig(test, true);
- }
- success ^= invert;
- if (orOp)
- ret |= success;
+ argsString += c;
+ }
+ if (!quoted && !parens && (isOp || d == ed)) {
+ if (m_cumulative || (orOp != ret)) {
+ if (isFunc)
+ ret = evaluateConditionalFunction(ProString(test), ProString(argsString, NoHash));
else
- ret &= success;
- orOp = (c == '|');
- invert = false;
- isFunc = false;
- test.clear();
- args.clear();
+ ret = isActiveConfig(test, true);
+ ret ^= invert;
}
+ orOp = (c == '|');
+ invert = false;
+ isFunc = false;
+ test.clear();
+ argsString.clear();
}
}
return returnBool(ret);
case T_CONFIG: {
if (args.count() < 1 || args.count() > 2) {
logMessage(format("CONFIG(config) requires one or two arguments."));
- return ProItem::ReturnFalse;
+ return ReturnFalse;
}
if (args.count() == 1)
- return returnBool(isActiveConfig(args.first()));
- const QStringList mutuals = args[1].split(QLatin1Char('|'));
- const QStringList &configs = valuesDirect(statics.strCONFIG);
+ return returnBool(isActiveConfig(args.at(0).toQString(m_tmp2)));
+ const QStringList &mutuals = args.at(1).toQString(m_tmp2).split(QLatin1Char('|'));
+ const ProStringList &configs = valuesDirect(statics.strCONFIG);
for (int i = configs.size() - 1; i >= 0; i--) {
for (int mut = 0; mut < mutuals.count(); mut++) {
}
}
}
- return ProItem::ReturnFalse;
+ return ReturnFalse;
}
case T_CONTAINS: {
if (args.count() < 2 || args.count() > 3) {
logMessage(format("contains(var, val) requires two or three arguments."));
- return ProItem::ReturnFalse;
+ return ReturnFalse;
}
- const QString &qry = args.at(1);
+ const QString &qry = args.at(1).toQString(m_tmp1);
QRegExp regx;
- if (qry != QRegExp::escape(qry))
- regx.setPattern(qry);
- const QStringList &l = values(map(args.first()));
+ if (qry != QRegExp::escape(qry)) {
+ QString copy = qry;
+ copy.detach();
+ regx.setPattern(copy);
+ }
+ const ProStringList &l = values(map(args.at(0)));
if (args.count() == 2) {
+ int t = 0;
for (int i = 0; i < l.size(); ++i) {
- const QString val = l[i];
- if ((!regx.isEmpty() && regx.exactMatch(val)) || val == qry)
- return ProItem::ReturnTrue;
+ const ProString &val = l[i];
+ if ((!regx.isEmpty() && regx.exactMatch(val.toQString(m_tmp[t]))) || val == qry)
+ return ReturnTrue;
+ t ^= 1;
}
} else {
- const QStringList mutuals = args[2].split(QLatin1Char('|'));
+ const QStringList &mutuals = args.at(2).toQString(m_tmp3).split(QLatin1Char('|'));
for (int i = l.size() - 1; i >= 0; i--) {
- const QString val = l[i];
+ const ProString val = l[i];
for (int mut = 0; mut < mutuals.count(); mut++) {
if (val == mutuals[mut].trimmed()) {
- return returnBool((!regx.isEmpty() && regx.exactMatch(val))
+ return returnBool((!regx.isEmpty()
+ && regx.exactMatch(val.toQString(m_tmp2)))
|| val == qry);
}
}
}
}
- return ProItem::ReturnFalse;
+ return ReturnFalse;
}
case T_COUNT: {
if (args.count() != 2 && args.count() != 3) {
logMessage(format("count(var, count, op=\"equals\") requires two or three arguments."));
- return ProItem::ReturnFalse;
+ return ReturnFalse;
}
- int cnt = values(map(args.first())).count();
+ int cnt = values(map(args.at(0))).count();
if (args.count() == 3) {
- QString comp = args[2];
+ const ProString &comp = args.at(2);
+ const int val = args.at(1).toQString(m_tmp1).toInt();
if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) {
- return returnBool(cnt > args[1].toInt());
+ return returnBool(cnt > val);
} else if (comp == QLatin1String(">=")) {
- return returnBool(cnt >= args[1].toInt());
+ return returnBool(cnt >= val);
} else if (comp == QLatin1String("<") || comp == QLatin1String("lessThan")) {
- return returnBool(cnt < args[1].toInt());
+ return returnBool(cnt < val);
} else if (comp == QLatin1String("<=")) {
- return returnBool(cnt <= args[1].toInt());
+ return returnBool(cnt <= val);
} else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual")
|| comp == QLatin1String("=") || comp == QLatin1String("==")) {
- return returnBool(cnt == args[1].toInt());
+ return returnBool(cnt == val);
} else {
- logMessage(format("unexpected modifier to count(%2)").arg(comp));
- return ProItem::ReturnFalse;
+ logMessage(format("unexpected modifier to count(%2)")
+ .arg(comp.toQString(m_tmp1)));
+ return ReturnFalse;
}
}
- return returnBool(cnt == args[1].toInt());
+ return returnBool(cnt == args.at(1).toQString(m_tmp1).toInt());
}
case T_GREATERTHAN:
case T_LESSTHAN: {
if (args.count() != 2) {
- logMessage(format("%1(variable, value) requires two arguments.").arg(function));
- return ProItem::ReturnFalse;
+ logMessage(format("%1(variable, value) requires two arguments.")
+ .arg(function.toQString(m_tmp1)));
+ return ReturnFalse;
}
- QString rhs(args[1]), lhs(values(map(args.at(0))).join(statics.field_sep));
+ const QString &rhs(args.at(1).toQString(m_tmp1)),
+ &lhs(values(map(args.at(0))).join(statics.field_sep));
bool ok;
int rhs_int = rhs.toInt(&ok);
if (ok) { // do integer compare
}
case T_EQUALS:
if (args.count() != 2) {
- logMessage(format("%1(variable, value) requires two arguments.").arg(function));
- return ProItem::ReturnFalse;
+ logMessage(format("%1(variable, value) requires two arguments.")
+ .arg(function.toQString(m_tmp1)));
+ return ReturnFalse;
}
- return returnBool(values(map(args.at(0))).join(statics.field_sep) == args.at(1));
+ return returnBool(values(map(args.at(0))).join(statics.field_sep)
+ == args.at(1).toQString(m_tmp1));
case T_CLEAR: {
if (m_skipLevel && !m_cumulative)
- return ProItem::ReturnFalse;
+ return ReturnFalse;
if (args.count() != 1) {
- logMessage(format("%1(variable) requires one argument.").arg(function));
- return ProItem::ReturnFalse;
+ logMessage(format("%1(variable) requires one argument.")
+ .arg(function.toQString(m_tmp1)));
+ return ReturnFalse;
}
- QHash<QString, QStringList> *hsh;
- QHash<QString, QStringList>::Iterator it;
- const QString &var = map(args.at(0));
+ QHash<ProString, ProStringList> *hsh;
+ QHash<ProString, ProStringList>::Iterator it;
+ const ProString &var = map(args.at(0));
if (!(hsh = findValues(var, &it)))
- return ProItem::ReturnFalse;
+ return ReturnFalse;
if (hsh == &m_valuemapStack.top())
it->clear();
else
m_valuemapStack.top()[var].clear();
- return ProItem::ReturnTrue;
+ return ReturnTrue;
}
case T_UNSET: {
if (m_skipLevel && !m_cumulative)
- return ProItem::ReturnFalse;
+ return ReturnFalse;
if (args.count() != 1) {
- logMessage(format("%1(variable) requires one argument.").arg(function));
- return ProItem::ReturnFalse;
+ logMessage(format("%1(variable) requires one argument.")
+ .arg(function.toQString(m_tmp1)));
+ return ReturnFalse;
}
- QHash<QString, QStringList> *hsh;
- QHash<QString, QStringList>::Iterator it;
- const QString &var = map(args.at(0));
+ QHash<ProString, ProStringList> *hsh;
+ QHash<ProString, ProStringList>::Iterator it;
+ const ProString &var = map(args.at(0));
if (!(hsh = findValues(var, &it)))
- return ProItem::ReturnFalse;
+ return ReturnFalse;
if (m_valuemapStack.size() == 1)
hsh->erase(it);
else if (hsh == &m_valuemapStack.top())
*it = statics.fakeValue;
else
m_valuemapStack.top()[var] = statics.fakeValue;
- return ProItem::ReturnTrue;
+ return ReturnTrue;
}
case T_INCLUDE: {
if (m_skipLevel && !m_cumulative)
- return ProItem::ReturnFalse;
+ return ReturnFalse;
QString parseInto;
// the third optional argument to include() controls warnings
// and is not used here
if ((args.count() == 2) || (args.count() == 3) ) {
- parseInto = args[1];
+ parseInto = args.at(1).toQString(m_tmp2);
} else if (args.count() != 1) {
logMessage(format("include(file, into, silent) requires one, two or three arguments."));
- return ProItem::ReturnFalse;
+ return ReturnFalse;
}
- QString fn = resolvePath(expandEnvVars(args.first()));
+ QString fn = resolvePath(expandEnvVars(args.at(0).toQString()));
bool ok;
if (parseInto.isEmpty()) {
- State sts = m_sts;
ok = evaluateFile(fn);
- m_sts = sts;
} else {
- QHash<QString, QStringList> symbols;
+ QHash<ProString, ProStringList> symbols;
if ((ok = evaluateFileInto(fn, &symbols, 0))) {
- QHash<QString, QStringList> newMap;
- for (QHash<QString, QStringList>::ConstIterator
+ QHash<ProString, ProStringList> newMap;
+ for (QHash<ProString, ProStringList>::ConstIterator
it = m_valuemapStack.top().constBegin(),
end = m_valuemapStack.top().constEnd();
- it != end; ++it)
- if (!(it.key().startsWith(parseInto) &&
- (it.key().length() == parseInto.length()
- || it.key().at(parseInto.length()) == QLatin1Char('.'))))
+ it != end; ++it) {
+ const QString &ky = it.key().toQString(m_tmp1);
+ if (!(ky.startsWith(parseInto) &&
+ (ky.length() == parseInto.length()
+ || ky.at(parseInto.length()) == QLatin1Char('.'))))
newMap[it.key()] = it.value();
- for (QHash<QString, QStringList>::ConstIterator it = symbols.constBegin();
- it != symbols.constEnd(); ++it)
- if (!it.key().startsWith(QLatin1Char('.')))
- newMap.insert(parseInto + QLatin1Char('.') + it.key(), it.value());
+ }
+ for (QHash<ProString, ProStringList>::ConstIterator it = symbols.constBegin();
+ it != symbols.constEnd(); ++it) {
+ const QString &ky = it.key().toQString(m_tmp1);
+ if (!ky.startsWith(QLatin1Char('.')))
+ newMap.insert(ProString(parseInto + QLatin1Char('.') + ky), it.value());
+ }
m_valuemapStack.top() = newMap;
}
}
}
case T_LOAD: {
if (m_skipLevel && !m_cumulative)
- return ProItem::ReturnFalse;
+ return ReturnFalse;
bool ignore_error = false;
if (args.count() == 2) {
- QString sarg = args[1];
- ignore_error = (!sarg.compare(statics.strtrue, Qt::CaseInsensitive) || sarg.toInt());
+ ignore_error = isTrue(args.at(1), m_tmp2);
} else if (args.count() != 1) {
logMessage(format("load(feature) requires one or two arguments."));
- return ProItem::ReturnFalse;
+ return ReturnFalse;
}
// XXX ignore_error unused
- return returnBool(evaluateFeatureFile(expandEnvVars(args.first())));
+ return returnBool(evaluateFeatureFile(expandEnvVars(args.at(0).toQString())));
}
case T_DEBUG:
// Yup - do nothing. Nothing is going to enable debug output anyway.
- return ProItem::ReturnFalse;
+ return ReturnFalse;
case T_MESSAGE: {
if (args.count() != 1) {
- logMessage(format("%1(message) requires one argument.").arg(function));
- return ProItem::ReturnFalse;
+ logMessage(format("%1(message) requires one argument.")
+ .arg(function.toQString(m_tmp1)));
+ return ReturnFalse;
}
- QString msg = expandEnvVars(args.first());
- fileMessage(QString::fromLatin1("Project %1: %2").arg(function.toUpper(), msg));
+ const QString &msg = expandEnvVars(args.at(0).toQString(m_tmp2));
+ fileMessage(QString::fromLatin1("Project %1: %2")
+ .arg(function.toQString(m_tmp1).toUpper(), msg));
// ### Consider real termination in non-cumulative mode
return returnBool(function != QLatin1String("error"));
}
case T_SYSTEM: {
if (args.count() != 1) {
logMessage(format("system(exec) requires one argument."));
- ProItem::ReturnFalse;
+ ReturnFalse;
}
return returnBool(system((QLatin1String("cd ")
+ IoUtils::shellQuote(currentDirectory())
- + QLatin1String(" && ") + args.first()).toLocal8Bit().constData()) == 0);
+ + QLatin1String(" && ") + args.at(0)).toLocal8Bit().constData()) == 0);
}
#endif
case T_ISEMPTY: {
if (args.count() != 1) {
logMessage(format("isEmpty(var) requires one argument."));
- return ProItem::ReturnFalse;
+ return ReturnFalse;
}
- QStringList sl = values(map(args.first()));
+ const ProStringList &sl = values(map(args.at(0)));
if (sl.count() == 0) {
- return ProItem::ReturnTrue;
+ return ReturnTrue;
} else if (sl.count() > 0) {
- QString var = sl.first();
+ const ProString &var = sl.first();
if (var.isEmpty())
- return ProItem::ReturnTrue;
+ return ReturnTrue;
}
- return ProItem::ReturnFalse;
+ return ReturnFalse;
}
case T_EXISTS: {
if (args.count() != 1) {
logMessage(format("exists(file) requires one argument."));
- return ProItem::ReturnFalse;
+ return ReturnFalse;
}
- QString file = resolvePath(expandEnvVars(args.first()));
+ const QString &file = resolvePath(expandEnvVars(args.at(0).toQString(m_tmp1)));
if (IoUtils::exists(file)) {
- return ProItem::ReturnTrue;
+ return ReturnTrue;
}
int slsh = file.lastIndexOf(QLatin1Char('/'));
QString fn = file.mid(slsh+1);
if (fn.contains(QLatin1Char('*')) || fn.contains(QLatin1Char('?'))) {
QString dirstr = file.left(slsh+1);
if (!QDir(dirstr).entryList(QStringList(fn)).isEmpty())
- return ProItem::ReturnTrue;
+ return ReturnTrue;
}
- return ProItem::ReturnFalse;
+ return ReturnFalse;
}
case 0:
- logMessage(format("'%1' is not a recognized test function").arg(function));
- return ProItem::ReturnFalse;
+ logMessage(format("'%1' is not a recognized test function")
+ .arg(function.toQString(m_tmp1)));
+ return ReturnFalse;
default:
- logMessage(format("Function '%1' is not implemented").arg(function));
- return ProItem::ReturnFalse;
+ logMessage(format("Function '%1' is not implemented").arg(function.toQString(m_tmp1)));
+ return ReturnFalse;
}
}
-QHash<QString, QStringList> *ProFileEvaluator::Private::findValues(
- const QString &variableName, QHash<QString, QStringList>::Iterator *rit)
+QHash<ProString, ProStringList> *ProFileEvaluator::Private::findValues(
+ const ProString &variableName, QHash<ProString, ProStringList>::Iterator *rit)
{
for (int i = m_valuemapStack.size(); --i >= 0; ) {
- QHash<QString, QStringList>::Iterator it = m_valuemapStack[i].find(variableName);
+ QHash<ProString, ProStringList>::Iterator it = m_valuemapStack[i].find(variableName);
if (it != m_valuemapStack[i].end()) {
if (it->constBegin() == statics.fakeValue.constBegin())
return 0;
return 0;
}
-QStringList &ProFileEvaluator::Private::valuesRef(const QString &variableName)
+ProStringList &ProFileEvaluator::Private::valuesRef(const ProString &variableName)
{
- QHash<QString, QStringList>::Iterator it = m_valuemapStack.top().find(variableName);
+ QHash<ProString, ProStringList>::Iterator it = m_valuemapStack.top().find(variableName);
if (it != m_valuemapStack.top().end())
return *it;
for (int i = m_valuemapStack.size() - 1; --i >= 0; ) {
- QHash<QString, QStringList>::ConstIterator it = m_valuemapStack.at(i).constFind(variableName);
+ QHash<ProString, ProStringList>::ConstIterator it = m_valuemapStack.at(i).constFind(variableName);
if (it != m_valuemapStack.at(i).constEnd()) {
- QStringList &ret = m_valuemapStack.top()[variableName];
+ ProStringList &ret = m_valuemapStack.top()[variableName];
ret = *it;
return ret;
}
return m_valuemapStack.top()[variableName];
}
-QStringList ProFileEvaluator::Private::valuesDirect(const QString &variableName) const
+ProStringList ProFileEvaluator::Private::valuesDirect(const ProString &variableName) const
{
for (int i = m_valuemapStack.size(); --i >= 0; ) {
- QHash<QString, QStringList>::ConstIterator it = m_valuemapStack.at(i).constFind(variableName);
+ QHash<ProString, ProStringList>::ConstIterator it = m_valuemapStack.at(i).constFind(variableName);
if (it != m_valuemapStack.at(i).constEnd()) {
if (it->constBegin() == statics.fakeValue.constBegin())
break;
return *it;
}
}
- return QStringList();
+ return ProStringList();
}
-QStringList ProFileEvaluator::Private::values(const QString &variableName) const
+ProStringList ProFileEvaluator::Private::values(const ProString &variableName) const
{
- QHash<QString, int>::ConstIterator vli = statics.varList.find(variableName);
+ QHash<ProString, int>::ConstIterator vli = statics.varList.find(variableName);
if (vli != statics.varList.constEnd()) {
int vlidx = *vli;
QString ret;
}
#endif
}
- return QStringList(ret);
+ return ProStringList(ProString(ret, NoHash));
}
- QStringList result = valuesDirect(variableName);
+ ProStringList result = valuesDirect(variableName);
if (result.isEmpty()) {
if (variableName == statics.strTEMPLATE) {
- result.append(QLatin1String("app"));
+ result.append(ProString("app", NoHash));
} else if (variableName == statics.strQMAKE_DIR_SEP) {
- result.append(m_option->dirlist_sep);
+ result.append(ProString(m_option->dirlist_sep, NoHash));
}
}
return result;
bool ProFileEvaluator::Private::evaluateFileDirect(
const QString &fileName, ProFileEvaluator::EvalFileType type)
{
+ int lineNo = m_lineNo;
if (ProFile *pro = parsedProFile(fileName, true)) {
q->aboutToEval(currentProFile(), pro, type);
- bool ok = (visitProFile(pro) == ProItem::ReturnTrue);
+ bool ok = (visitProFile(pro) == ReturnTrue);
q->doneWithEval(currentProFile());
pro->deref();
+ m_lineNo = lineNo;
return ok;
} else {
+ m_lineNo = lineNo;
return false;
}
}
}
bool ProFileEvaluator::Private::evaluateFeatureFile(
- const QString &fileName, QHash<QString, QStringList> *values, FunctionDefs *funcs)
+ const QString &fileName, QHash<ProString, ProStringList> *values, FunctionDefs *funcs)
{
QString fn = fileName;
if (!fn.endsWith(QLatin1String(".prf")))
cool:
// It's beyond me why qmake has this inside this if ...
- QStringList &already = valuesRef(QLatin1String("QMAKE_INTERNAL_INCLUDED_FEATURES"));
- if (already.contains(fn))
+ ProStringList &already = valuesRef(ProString("QMAKE_INTERNAL_INCLUDED_FEATURES"));
+ ProString afn(fn, NoHash);
+ if (already.contains(afn))
return true;
- already.append(fn);
+ already.append(afn);
} else {
fn = resolvePath(fn);
}
}
bool ProFileEvaluator::Private::evaluateFileInto(
- const QString &fileName, QHash<QString, QStringList> *values, FunctionDefs *funcs)
+ const QString &fileName, QHash<ProString, ProStringList> *values, FunctionDefs *funcs)
{
ProFileEvaluator visitor(m_option);
visitor.d->m_cumulative = false;
if (!visitor.d->evaluateFile(fileName))
return false;
*values = visitor.d->m_valuemapStack.top();
- if (funcs) {
+ if (funcs)
*funcs = visitor.d->m_functionDefs;
- // So they are not unref'd
- visitor.d->m_functionDefs.testFunctions.clear();
- visitor.d->m_functionDefs.replaceFunctions.clear();
- }
return true;
}
bool ProFileEvaluator::contains(const QString &variableName) const
{
- return d->m_valuemapStack.top().contains(variableName);
+ return d->m_valuemapStack.top().contains(ProString(variableName));
+}
+
+static QStringList expandEnvVars(const ProStringList &x)
+{
+ QStringList ret;
+ foreach (const ProString &str, x)
+ ret << expandEnvVars(str.toQString());
+ return ret;
}
QStringList ProFileEvaluator::values(const QString &variableName) const
{
- return expandEnvVars(d->values(variableName));
+ return expandEnvVars(d->values(ProString(variableName)));
}
QStringList ProFileEvaluator::values(const QString &variableName, const ProFile *pro) const
{
// It makes no sense to put any kind of magic into expanding these
- return expandEnvVars(d->m_filevaluemap.value(pro).value(variableName));
+ return expandEnvVars(d->m_filevaluemap.value(pro).value(ProString(variableName)));
}
QStringList ProFileEvaluator::absolutePathValues(
{
absEl = QDir::cleanPath(absEl);
int nameOff = absEl.lastIndexOf(QLatin1Char('/'));
- QString absDir = QString::fromRawData(absEl.constData(), nameOff);
+ QString absDir = d->m_tmp1.setRawData(absEl.constData(), nameOff);
if (IoUtils::exists(absDir)) {
- QString wildcard = QString::fromRawData(absEl.constData() + nameOff + 1,
+ QString wildcard = d->m_tmp2.setRawData(absEl.constData() + nameOff + 1,
absEl.length() - nameOff - 1);
if (wildcard.contains(QLatin1Char('*')) || wildcard.contains(QLatin1Char('?'))) {
QDir theDir(absDir);
ProFileEvaluator::TemplateType ProFileEvaluator::templateType()
{
- QStringList templ = values(statics.strTEMPLATE);
+ const ProStringList &templ = d->values(statics.strTEMPLATE);
if (templ.count() >= 1) {
- const QString &t = templ.last();
+ const QString &t = templ.last().toQString();
if (!t.compare(QLatin1String("app"), Qt::CaseInsensitive))
return TT_Application;
if (!t.compare(QLatin1String("lib"), Qt::CaseInsensitive))
class Private;
public:
+ struct FunctionDef {
+ QString string;
+ int offset;
+ };
+
struct FunctionDefs {
- QHash<QString, ProBlock *> testFunctions;
- QHash<QString, ProBlock *> replaceFunctions;
+ QHash<ProString, FunctionDef> testFunctions;
+ QHash<ProString, FunctionDef> replaceFunctions;
};
enum TemplateType {
virtual ~ProFileEvaluator();
ProFileEvaluator::TemplateType templateType();
- virtual bool contains(const QString &variableName) const;
void setVerbose(bool on); // Default is false
void setCumulative(bool on); // Default is true!
void setOutputDir(const QString &dir); // Default is empty
ProFile *parsedProFile(const QString &fileName, const QString &contents = QString());
bool accept(ProFile *pro);
+ bool contains(const QString &variableName) const;
QStringList values(const QString &variableName) const;
QStringList values(const QString &variableName, const ProFile *pro) const;
QStringList absolutePathValues(const QString &variable, const QString &baseDirectory) const;
friend class ProFileCache;
};
+Q_DECLARE_TYPEINFO(ProFileEvaluator::FunctionDef, Q_MOVABLE_TYPE);
+
class ProFileCache
{
public:
private:
friend class ProFileEvaluator;
friend class ProFileEvaluator::Private;
- QHash<QString, QStringList> base_valuemap; // Cached results of qmake.conf, .qmake.cache & default_pre.prf
+ QHash<ProString, ProStringList> base_valuemap; // Cached results of qmake.conf, .qmake.cache & default_pre.prf
ProFileEvaluator::FunctionDefs base_functions;
QStringList feature_roots;
QString qmakespec_name;
#include "proitems.h"
#include <QtCore/QFileInfo>
+#include <QtCore/QSet>
QT_BEGIN_NAMESPACE
-ProBlock::ProBlock()
- : ProItem(BlockKind)
+using namespace ProStringConstants;
+
+// from qhash.cpp
+uint ProString::hash(const QChar *p, int n)
{
- m_proitems = 0;
- m_blockKind = 0;
- m_refCount = 1;
+ uint h = 0;
+
+ while (n--) {
+ h = (h << 4) + (*p++).unicode();
+ h ^= (h & 0xf0000000) >> 23;
+ h &= 0x0fffffff;
+ }
+ return h;
}
-ProBlock::~ProBlock()
+ProString::ProString() :
+ m_offset(0), m_length(0), m_hash(0x80000000)
{
- for (ProItem *itm, *nitm = m_proitems; (itm = nitm); ) {
- nitm = itm->m_next;
- switch (itm->kind()) {
- case BlockKind: static_cast<ProBlock *>(itm)->deref(); break;
- case FunctionKind: delete static_cast<ProFunction *>(itm); break;
- case ConditionKind: delete static_cast<ProCondition *>(itm); break;
- case OperatorKind: delete static_cast<ProOperator *>(itm); break;
- case VariableKind: delete static_cast<ProVariable *>(itm); break;
+}
+
+ProString::ProString(const ProString &other) :
+ m_string(other.m_string), m_offset(other.m_offset), m_length(other.m_length), m_hash(other.m_hash)
+{
+}
+
+ProString::ProString(const ProString &other, OmitPreHashing) :
+ m_string(other.m_string), m_offset(other.m_offset), m_length(other.m_length), m_hash(0x80000000)
+{
+}
+
+ProString::ProString(const QString &str) :
+ m_string(str), m_offset(0), m_length(str.length())
+{
+ updatedHash();
+}
+
+ProString::ProString(const QString &str, OmitPreHashing) :
+ m_string(str), m_offset(0), m_length(str.length()), m_hash(0x80000000)
+{
+}
+
+ProString::ProString(const char *str) :
+ m_string(QString::fromLatin1(str)), m_offset(0), m_length(qstrlen(str))
+{
+ updatedHash();
+}
+
+ProString::ProString(const char *str, OmitPreHashing) :
+ m_string(QString::fromLatin1(str)), m_offset(0), m_length(qstrlen(str)), m_hash(0x80000000)
+{
+}
+
+ProString::ProString(const QString &str, int offset, int length) :
+ m_string(str), m_offset(offset), m_length(length)
+{
+ updatedHash();
+}
+
+ProString::ProString(const QString &str, int offset, int length, uint hash) :
+ m_string(str), m_offset(offset), m_length(length), m_hash(hash)
+{
+}
+
+ProString::ProString(const QString &str, int offset, int length, ProStringConstants::OmitPreHashing) :
+ m_string(str), m_offset(offset), m_length(length), m_hash(0x80000000)
+{
+}
+
+uint ProString::updatedHash() const
+{
+ return (m_hash = hash(m_string.constData() + m_offset, m_length));
+}
+
+uint qHash(const ProString &str)
+{
+ if (!(str.m_hash & 0x80000000))
+ return str.m_hash;
+ return str.updatedHash();
+}
+
+QString ProString::toQString() const
+{
+ return m_string.mid(m_offset, m_length);
+}
+
+QString &ProString::toQString(QString &tmp) const
+{
+ return tmp.setRawData(m_string.constData() + m_offset, m_length);
+}
+
+bool ProString::operator==(const ProString &other) const
+{
+ if (m_length != other.m_length)
+ return false;
+ return !memcmp(m_string.constData() + m_offset,
+ other.m_string.constData() + other.m_offset, m_length * 2);
+}
+
+bool ProString::operator==(const QString &other) const
+{
+ if (m_length != other.length())
+ return false;
+ return !memcmp(m_string.constData() + m_offset, other.constData(), m_length * 2);
+}
+
+bool ProString::operator==(const QLatin1String &other) const
+{
+ const ushort *uc = (ushort *)m_string.constData() + m_offset;
+ const ushort *e = uc + m_length;
+ const uchar *c = (uchar *)other.latin1();
+
+ if (!c)
+ return isEmpty();
+
+ while (*c) {
+ if (uc == e || *uc != *c)
+ return false;
+ ++uc;
+ ++c;
+ }
+ return (uc == e);
+}
+
+QChar *ProString::prepareAppend(int extraLen)
+{
+ if (m_string.isDetached() && m_length + extraLen <= m_string.capacity()) {
+ m_string.reserve(0); // Prevent the resize() below from reallocating
+ QChar *ptr = (QChar *)m_string.constData();
+ if (m_offset)
+ memmove(ptr, ptr + m_offset, m_length * 2);
+ ptr += m_length;
+ m_offset = 0;
+ m_length += extraLen;
+ m_string.resize(m_length);
+ m_hash = 0x80000000;
+ return ptr;
+ } else {
+ QString neu(m_length + extraLen, Qt::Uninitialized);
+ QChar *ptr = (QChar *)neu.constData();
+ memcpy(ptr, m_string.constData() + m_offset, m_length * 2);
+ ptr += m_length;
+ *this = ProString(neu, NoHash);
+ return ptr;
+ }
+}
+
+// If pending != 0, prefix with space if appending to non-empty non-pending
+ProString &ProString::append(const ProString &other, bool *pending)
+{
+ if (other.m_length) {
+ if (!m_length) {
+ *this = other;
+ } else {
+ QChar *ptr;
+ if (pending && !*pending) {
+ ptr = prepareAppend(1 + other.m_length);
+ *ptr++ = 32;
+ } else {
+ ptr = prepareAppend(other.m_length);
+ }
+ memcpy(ptr, other.m_string.constData() + other.m_offset, other.m_length * 2);
}
+ if (pending)
+ *pending = true;
}
+ return *this;
}
-ProFile::ProFile(const QString &fileName)
- : ProBlock()
+ProString &ProString::append(const ProStringList &other, bool *pending, bool skipEmpty1st)
+{
+ if (const int sz = other.size()) {
+ int startIdx = 0;
+ if (pending && !*pending && skipEmpty1st && other.at(0).isEmpty()) {
+ if (sz == 1)
+ return *this;
+ startIdx = 1;
+ }
+ if (!m_length && sz == startIdx + 1) {
+ *this = other.at(startIdx);
+ } else {
+ int totalLength = sz - startIdx;
+ for (int i = startIdx; i < sz; ++i)
+ totalLength += other.at(i).size();
+ bool putSpace = false;
+ if (pending && !*pending && m_length)
+ putSpace = true;
+ else
+ totalLength--;
+
+ QChar *ptr = prepareAppend(totalLength);
+ for (int i = startIdx; i < sz; ++i) {
+ if (putSpace)
+ *ptr++ = 32;
+ else
+ putSpace = true;
+ const ProString &str = other.at(i);
+ memcpy(ptr, str.m_string.constData() + str.m_offset, str.m_length * 2);
+ ptr += str.m_length;
+ }
+ }
+ if (pending)
+ *pending = true;
+ }
+ return *this;
+}
+
+QString operator+(const ProString &one, const ProString &two)
+{
+ if (two.m_length) {
+ if (!one.m_length) {
+ return two.toQString();
+ } else {
+ QString neu(one.m_length + two.m_length, Qt::Uninitialized);
+ ushort *ptr = (ushort *)neu.constData();
+ memcpy(ptr, one.m_string.constData() + one.m_offset, one.m_length * 2);
+ memcpy(ptr + one.m_length, two.m_string.constData() + two.m_offset, two.m_length * 2);
+ return neu;
+ }
+ }
+ return one.toQString();
+}
+
+
+ProString ProString::mid(int off, int len) const
+{
+ ProString ret(*this, NoHash);
+ if (off > m_length)
+ off = m_length;
+ ret.m_offset += off;
+ ret.m_length -= off;
+ if (ret.m_length > len)
+ ret.m_length = len;
+ return ret;
+}
+
+ProString ProString::trimmed() const
+{
+ ProString ret(*this, NoHash);
+ int cur = m_offset;
+ int end = cur + m_length;
+ const QChar *data = m_string.constData();
+ for (; cur < end; cur++)
+ if (!data[cur].isSpace()) {
+ // No underrun check - we know there is at least one non-whitespace
+ while (data[end - 1].isSpace())
+ end--;
+ break;
+ }
+ ret.m_offset = cur;
+ ret.m_length = end - cur;
+ return ret;
+}
+
+QString ProStringList::join(const QString &sep) const
+{
+ int totalLength = 0;
+ const int sz = size();
+
+ for (int i = 0; i < sz; ++i)
+ totalLength += at(i).size();
+
+ if (sz)
+ totalLength += sep.size() * (sz - 1);
+
+ QString res(totalLength, Qt::Uninitialized);
+ QChar *ptr = (QChar *)res.constData();
+ for (int i = 0; i < sz; ++i) {
+ if (i) {
+ memcpy(ptr, sep.constData(), sep.size() * 2);
+ ptr += sep.size();
+ }
+ memcpy(ptr, at(i).constData(), at(i).size() * 2);
+ ptr += at(i).size();
+ }
+ return res;
+}
+
+void ProStringList::removeDuplicates()
{
- setBlockKind(ProBlock::ProFileKind);
- m_fileName = fileName;
+ int n = size();
+ int j = 0;
+ QSet<ProString> seen;
+ seen.reserve(n);
+ for (int i = 0; i < n; ++i) {
+ const ProString &s = at(i);
+ if (seen.contains(s))
+ continue;
+ seen.insert(s);
+ if (j != i)
+ (*this)[j] = s;
+ ++j;
+ }
+ if (n != j)
+ erase(begin() + j, end());
+}
+ProFile::ProFile(const QString &fileName)
+ : m_refCount(1),
+ m_fileName(fileName)
+{
int nameOff = fileName.lastIndexOf(QLatin1Char('/'));
m_displayFileName = QString(fileName.constData() + nameOff + 1,
fileName.length() - nameOff - 1);
m_directoryName = QString(fileName.constData(), nameOff);
}
+ProFile::~ProFile()
+{
+}
+
QT_END_NAMESPACE
#define PROITEMS_H
#include <QtCore/QString>
-#include <QtCore/QList>
+#include <QtCore/QVector>
QT_BEGIN_NAMESPACE
#else
class ProItemRefCount {
public:
- ProItemRefCount() : m_cnt(0) {}
+ ProItemRefCount(int cnt = 0) : m_cnt(cnt) {}
bool ref() { return ++m_cnt != 0; }
bool deref() { return --m_cnt != 0; }
ProItemRefCount &operator=(int value) { m_cnt = value; return *this; }
};
#endif
-class ProItem
-{
-public:
- enum ProItemKind {
- FunctionKind,
- ConditionKind,
- OperatorKind,
- VariableKind,
- BlockKind
- };
-
- enum ProItemReturn {
- ReturnFalse,
- ReturnTrue,
- ReturnBreak,
- ReturnNext,
- ReturnLoop,
- ReturnSkip,
- ReturnReturn
- };
-
- ProItem(ProItemKind kind) : m_kind(kind), m_lineNumber(0) {}
-
- ProItemKind kind() const { return m_kind; }
-
- int lineNumber() const { return m_lineNumber; }
- void setLineNumber(int lineNumber) { m_lineNumber = lineNumber; }
-
- ProItem *next() const { return m_next; }
- ProItem **nextRef() { return &m_next; }
-
-private:
- ProItem *m_next;
- ProItemKind m_kind;
- int m_lineNumber;
-
- friend class ProBlock; // C++ is braindead ...
-};
-
-class ProBlock : public ProItem
-{
-public:
- enum ProBlockKind {
- NormalKind = 0x00,
- ScopeKind = 0x01,
- ScopeContentsKind = 0x02,
- ProFileKind = 0x08,
- FunctionBodyKind = 0x10,
- SingleLine = 0x80
- };
+namespace ProStringConstants {
+enum OmitPreHashing { NoHash };
+}
- ProBlock();
- ~ProBlock();
-
- void setBlockKind(int blockKind) { m_blockKind = blockKind; }
- int blockKind() const { return m_blockKind; }
-
- ProItem *items() const { return m_proitems; }
- ProItem **itemsRef() { return &m_proitems; }
-
- void ref() { m_refCount.ref(); }
- void deref() { if (!m_refCount.deref()) delete this; }
-
-private:
- ProItem *m_proitems;
- int m_blockKind;
- friend class ProFile; // for the pseudo-virtual d'tor
- ProItemRefCount m_refCount;
-};
+class ProStringList;
-class ProVariable : public ProItem
-{
+class ProString {
public:
- enum VariableOperator {
- AddOperator = 0,
- RemoveOperator = 1,
- ReplaceOperator = 2,
- SetOperator = 3,
- UniqueAddOperator = 4
- };
-
- ProVariable(const QString &name) : ProItem(VariableKind), m_variableKind(SetOperator), m_variable(name) {}
- void setVariableOperator(VariableOperator variableKind) { m_variableKind = variableKind; }
- VariableOperator variableOperator() const { return m_variableKind; }
- void setVariable(const QString &name) { m_variable = name; }
- QString variable() const { return m_variable; }
- void setValue(const QString &value) { m_value = value; }
- QString value() const { return m_value; }
+ ProString();
+ ProString(const ProString &other);
+ ProString(const ProString &other, ProStringConstants::OmitPreHashing);
+ explicit ProString(const QString &str);
+ ProString(const QString &str, ProStringConstants::OmitPreHashing);
+ explicit ProString(const char *str);
+ ProString(const char *str, ProStringConstants::OmitPreHashing);
+ ProString(const QString &str, int offset, int length);
+ ProString(const QString &str, int offset, int length, uint hash);
+ ProString(const QString &str, int offset, int length, ProStringConstants::OmitPreHashing);
+ QString toQString() const;
+ QString &toQString(QString &tmp) const;
+ ProString &operator+=(const ProString &other);
+ ProString &append(const ProString &other, bool *pending = 0);
+ ProString &append(const ProStringList &other, bool *pending = 0, bool skipEmpty1st = false);
+ bool operator==(const ProString &other) const;
+ bool operator==(const QString &other) const;
+ bool operator==(const QLatin1String &other) const;
+ bool operator!=(const ProString &other) const { return !(*this == other); }
+ bool operator!=(const QString &other) const { return !(*this == other); }
+ bool operator!=(const QLatin1String &other) const { return !(*this == other); }
+ bool isEmpty() const { return !m_length; }
+ int size() const { return m_length; }
+ const QChar *constData() const { return m_string.constData() + m_offset; }
+ ProString mid(int off, int len = -1) const;
+ ProString left(int len) const { return mid(0, len); }
+ ProString right(int len) const { return mid(qMax(0, size() - len)); }
+ ProString trimmed() const;
+ void clear() { m_string.clear(); m_length = 0; }
+
+ static uint hash(const QChar *p, int n);
private:
- VariableOperator m_variableKind;
- QString m_variable;
- QString m_value;
+ QString m_string;
+ int m_offset, m_length;
+ mutable uint m_hash;
+ QChar *prepareAppend(int extraLen);
+ uint updatedHash() const;
+ friend uint qHash(const ProString &str);
+ friend QString operator+(const ProString &one, const ProString &two);
};
+Q_DECLARE_TYPEINFO(ProString, Q_MOVABLE_TYPE);
-class ProFunction : public ProItem
-{
-public:
- explicit ProFunction(const QString &text) : ProItem(FunctionKind), m_text(text) {}
- void setText(const QString &text) { m_text = text; }
- QString text() const { return m_text; }
+uint qHash(const ProString &str);
+QString operator+(const ProString &one, const ProString &two);
+inline QString operator+(const ProString &one, const QString &two)
+ { return one + ProString(two, ProStringConstants::NoHash); }
+inline QString operator+(const QString &one, const ProString &two)
+ { return ProString(one, ProStringConstants::NoHash) + two; }
-private:
- QString m_text;
-};
-
-class ProCondition : public ProItem
-{
+class ProStringList : public QVector<ProString> {
public:
- explicit ProCondition(const QString &text) : ProItem(ConditionKind), m_text(text) {}
- void setText(const QString &text) { m_text = text; }
- QString text() const { return m_text; }
-
-private:
- QString m_text;
+ ProStringList() {}
+ ProStringList(const ProString &str) { *this << str; }
+ QString join(const QString &sep) const;
+ void removeDuplicates();
};
-class ProOperator : public ProItem
-{
-public:
- enum OperatorKind {
- OrOperator = 1,
- NotOperator = 2
- };
-
- explicit ProOperator(OperatorKind operatorKind) : ProItem(ProItem::OperatorKind), m_operatorKind(operatorKind) {}
- void setOperatorKind(OperatorKind operatorKind) { m_operatorKind = operatorKind; }
- OperatorKind operatorKind() const { return m_operatorKind; }
-
-private:
- OperatorKind m_operatorKind;
+// These token definitions affect both ProFileEvaluator and ProWriter
+enum ProToken {
+ TokTerminator = 0, // end of stream (possibly not included in length; must be zero)
+ TokLine, // line marker:
+ // - line (1)
+ TokAssign, // variable =
+ TokAppend, // variable +=
+ TokAppendUnique, // variable *=
+ TokRemove, // variable -=
+ TokReplace, // variable ~=
+ // previous literal/expansion is a variable manipulation
+ // - value expression + TokValueTerminator
+ TokValueTerminator, // assignment value terminator
+ TokLiteral, // literal string (fully dequoted)
+ // - length (1)
+ // - string data (length; unterminated)
+ TokHashLiteral, // literal string with hash (fully dequoted)
+ // - hash (2)
+ // - length (1)
+ // - string data (length; unterminated)
+ TokVariable, // qmake variable expansion
+ // - hash (2)
+ // - name length (1)
+ // - name (name length; unterminated)
+ TokProperty, // qmake property expansion
+ // - name length (1)
+ // - name (name length; unterminated)
+ TokEnvVar, // environment variable expansion
+ // - name length (1)
+ // - name (name length; unterminated)
+ TokFuncName, // replace function expansion
+ // - hash (2)
+ // - name length (1)
+ // - name (name length; unterminated)
+ // - ((nested expansion + TokArgSeparator)* + nested expansion)?
+ // - TokFuncTerminator
+ TokArgSeparator, // function argument separator
+ TokFuncTerminator, // function argument list terminator
+ TokCondition, // previous literal/expansion is a conditional
+ TokTestCall, // previous literal/expansion is a test function call
+ // - ((nested expansion + TokArgSeparator)* + nested expansion)?
+ // - TokFuncTerminator
+ TokNot, // '!' operator
+ TokAnd, // ':' operator
+ TokOr, // '|' operator
+ TokBranch, // branch point:
+ // - then block length (2)
+ // - then block + TokTerminator (then block length)
+ // - else block length (2)
+ // - else block + TokTerminator (else block length)
+ TokForLoop, // for loop:
+ // - variable name: hash (2), length (1), chars (length)
+ // - expression: length (2), bytes + TokValueTerminator (length)
+ // - body length (2)
+ // - body + TokTerminator (body length)
+ TokTestDef, // test function definition:
+ TokReplaceDef, // replace function definition:
+ // - function name: hash (2), length (1), chars (length)
+ // - body length (2)
+ // - body + TokTerminator (body length)
+ TokMask = 0xff,
+ TokQuoted = 0x100, // The expression is quoted => join expanded stringlist
+ TokNewStr = 0x200 // Next stringlist element
};
-class ProFile : public ProBlock
+class ProFile
{
public:
explicit ProFile(const QString &fileName);
+ ~ProFile();
QString displayFileName() const { return m_displayFileName; }
QString fileName() const { return m_fileName; }
QString directoryName() const { return m_directoryName; }
+ const QString &items() const { return m_proitems; }
+ QString *itemsRef() { return &m_proitems; }
- // d'tor is not virtual
+ void ref() { m_refCount.ref(); }
void deref() { if (!m_refCount.deref()) delete this; }
private:
+ ProItemRefCount m_refCount;
+ QString m_proitems;
QString m_fileName;
QString m_displayFileName;
QString m_directoryName;
using namespace Qt4ProjectManager::Internal;
-void ProWriter::addFiles(ProFile *profile, QStringList *lines,
- const QDir &proFileDir, const QStringList &filePaths,
- const QString &var)
+static uint getBlockLen(const ushort *&tokPtr)
{
+ uint len = *tokPtr++;
+ len |= (uint)*tokPtr++ << 16;
+ return len;
+}
+
+static bool getLiteral(const ushort *tokPtr, const ushort *tokEnd, QString &tmp)
+{
+ int count = 0;
+ while (tokPtr != tokEnd) {
+ ushort tok = *tokPtr++;
+ switch (tok & TokMask) {
+ case TokLine:
+ tokPtr++;
+ break;
+ case TokHashLiteral:
+ tokPtr += 2;
+ // fallthrough
+ case TokLiteral: {
+ uint len = *tokPtr++;
+ tmp.setRawData((const QChar *)tokPtr, len);
+ count++;
+ tokPtr += len;
+ break; }
+ default:
+ return false;
+ }
+ }
+ return count == 1;
+}
+
+static void skipStr(const ushort *&tokPtr)
+{
+ uint len = *tokPtr++;
+ tokPtr += len;
+}
+
+static void skipHashStr(const ushort *&tokPtr)
+{
+ tokPtr += 2;
+ uint len = *tokPtr++;
+ tokPtr += len;
+}
+
+static void skipBlock(const ushort *&tokPtr)
+{
+ uint len = getBlockLen(tokPtr);
+ tokPtr += len;
+}
+
+static void skipExpression(const ushort *&pTokPtr, int &lineNo)
+{
+ const ushort *tokPtr = pTokPtr;
+ forever {
+ ushort tok = *tokPtr++;
+ switch (tok) {
+ case TokLine:
+ lineNo = *tokPtr++;
+ break;
+ case TokValueTerminator:
+ case TokFuncTerminator:
+ pTokPtr = tokPtr;
+ return;
+ case TokArgSeparator:
+ break;
+ default:
+ switch (tok & TokMask) {
+ case TokLiteral:
+ case TokProperty:
+ case TokEnvVar:
+ skipStr(tokPtr);
+ break;
+ case TokHashLiteral:
+ case TokVariable:
+ skipHashStr(tokPtr);
+ break;
+ case TokFuncName:
+ skipHashStr(tokPtr);
+ pTokPtr = tokPtr;
+ skipExpression(pTokPtr, lineNo);
+ tokPtr = pTokPtr;
+ break;
+ default:
+ pTokPtr = tokPtr - 1;
+ return;
+ }
+ }
+ }
+}
+
+static const ushort *skipToken(ushort tok, const ushort *&tokPtr, int &lineNo)
+{
+ switch (tok) {
+ case TokLine:
+ lineNo = *tokPtr++;
+ break;
+ case TokAssign:
+ case TokAppend:
+ case TokAppendUnique:
+ case TokRemove:
+ case TokReplace:
+ tokPtr++;
+ // fallthrough
+ case TokTestCall:
+ skipExpression(tokPtr, lineNo);
+ break;
+ case TokForLoop:
+ skipHashStr(tokPtr);
+ // fallthrough
+ case TokBranch:
+ skipBlock(tokPtr);
+ skipBlock(tokPtr);
+ break;
+ case TokTestDef:
+ case TokReplaceDef:
+ skipHashStr(tokPtr);
+ skipBlock(tokPtr);
+ break;
+ case TokNot:
+ case TokAnd:
+ case TokOr:
+ case TokCondition:
+ break;
+ default: {
+ const ushort *oTokPtr = --tokPtr;
+ skipExpression(tokPtr, lineNo);
+ if (tokPtr != oTokPtr)
+ return oTokPtr;
+ }
+ Q_ASSERT_X(false, "skipToken", "unexpected item type");
+ }
+ return 0;
+}
+
+void ProWriter::addVarValues(ProFile *profile, QStringList *lines,
+ const QDir &proFileDir, const QStringList &values, const QString &var,
+ bool valuesAreFiles)
+{
+ QStringList valuesToWrite;
+ if (valuesAreFiles) {
+ foreach (const QString &v, values)
+ valuesToWrite << proFileDir.relativeFilePath(v);
+ } else {
+ valuesToWrite = values;
+ }
+
// Check if variable item exists as child of root item
- for (ProItem *item = profile->items(); item; item = item->next()) {
- if (item->kind() == ProItem::VariableKind) {
- ProVariable *proVar = static_cast<ProVariable*>(item);
- if (var == proVar->variable()
- && proVar->variableOperator() != ProVariable::RemoveOperator
- && proVar->variableOperator() != ProVariable::ReplaceOperator) {
-
- int lineNo = proVar->lineNumber() - 1;
- for (; lineNo < lines->count(); lineNo++) {
+ const ushort *tokPtr = (const ushort *)profile->items().constData();
+ int lineNo = 0;
+ QString tmp;
+ const ushort *lastXpr = 0;
+ while (ushort tok = *tokPtr++) {
+ if (tok == TokAssign || tok == TokAppend || tok == TokAppendUnique) {
+ if (getLiteral(lastXpr, tokPtr - 1, tmp) && var == tmp) {
+ for (--lineNo; lineNo < lines->count(); lineNo++) {
QString line = lines->at(lineNo);
int idx = line.indexOf(QLatin1Char('#'));
if (idx >= 0)
}
}
QString added;
- foreach (const QString &filePath, filePaths)
- added += QLatin1String(" ") + proFileDir.relativeFilePath(filePath)
- + QLatin1String(" \\\n");
+ foreach (const QString &v, valuesToWrite)
+ added += QLatin1String(" ") + v + QLatin1String(" \\\n");
added.chop(3);
lines->insert(lineNo, added);
return;
}
+ skipExpression(++tokPtr, lineNo);
+ } else {
+ lastXpr = skipToken(tok, tokPtr, lineNo);
}
}
// Create & append new variable item
QString added = QLatin1Char('\n') + var + QLatin1String(" +=");
- foreach (const QString &filePath, filePaths)
- added += QLatin1String(" \\\n ") + proFileDir.relativeFilePath(filePath);
+ foreach (const QString &v, valuesToWrite)
+ added += QLatin1String(" \\\n ") + v;
*lines << added;
}
-static void findProVariables(ProBlock *block, const QStringList &vars,
- QList<ProVariable *> *proVars)
+static void findProVariables(const ushort *tokPtr, const QStringList &vars,
+ QList<int> *proVars)
{
- for (ProItem *item = block->items(); item; item = item->next()) {
- if (item->kind() == ProItem::BlockKind) {
- findProVariables(static_cast<ProBlock*>(item), vars, proVars);
- } else if (item->kind() == ProItem::VariableKind) {
- ProVariable *proVar = static_cast<ProVariable*>(item);
- if (vars.contains(proVar->variable()))
- *proVars << proVar;
+ int lineNo = 0;
+ QString tmp;
+ const ushort *lastXpr = 0;
+ while (ushort tok = *tokPtr++) {
+ if (tok == TokBranch) {
+ uint blockLen = getBlockLen(tokPtr);
+ findProVariables(tokPtr, vars, proVars);
+ tokPtr += blockLen;
+ blockLen = getBlockLen(tokPtr);
+ findProVariables(tokPtr, vars, proVars);
+ tokPtr += blockLen;
+ } else if (tok == TokAssign || tok == TokAppend || tok == TokAppendUnique) {
+ if (getLiteral(lastXpr, tokPtr - 1, tmp) && vars.contains(tmp))
+ *proVars << lineNo;
+ skipExpression(++tokPtr, lineNo);
+ } else {
+ lastXpr = skipToken(tok, tokPtr, lineNo);
}
}
}
-QStringList ProWriter::removeFiles(ProFile *profile, QStringList *lines,
- const QDir &proFileDir, const QStringList &filePaths,
- const QStringList &vars)
+QStringList ProWriter::removeVarValues(ProFile *profile, QStringList *lines,
+ const QDir &proFileDir, const QStringList &values, const QStringList &vars,
+ bool valuesAreFiles)
{
- QStringList notChanged = filePaths;
+ QStringList notChanged = values;
- QList<ProVariable *> proVars;
- findProVariables(profile, vars, &proVars);
+ QList<int> varLines;
+ findProVariables((const ushort *)profile->items().constData(), vars, &varLines);
- // This is a tad stupid - basically, it can remove only entries which
- // the above code added.
- QStringList relativeFilePaths;
- foreach (const QString &absoluteFilePath, filePaths)
- relativeFilePaths << proFileDir.relativeFilePath(absoluteFilePath);
+ QStringList valuesToFind;
+ if (valuesAreFiles) {
+ // This is a tad stupid - basically, it can remove only entries which
+ // the above code added.
+ foreach (const QString &absoluteFilePath, values)
+ valuesToFind << proFileDir.relativeFilePath(absoluteFilePath);
+ } else {
+ valuesToFind = values;
+ }
// This code expects proVars to be sorted by the variables' appearance in the file.
int delta = 1;
- foreach (ProVariable *proVar, proVars) {
- if (proVar->variableOperator() != ProVariable::RemoveOperator
- && proVar->variableOperator() != ProVariable::ReplaceOperator) {
-
- bool first = true;
- int lineNo = proVar->lineNumber() - delta;
- typedef QPair<int, int> ContPos;
- QList<ContPos> contPos;
- while (lineNo < lines->count()) {
- QString &line = (*lines)[lineNo];
- int lineLen = line.length();
- bool killed = false;
- bool saved = false;
- int idx = line.indexOf(QLatin1Char('#'));
- if (idx >= 0)
- lineLen = idx;
- QChar *chars = line.data();
- forever {
- if (!lineLen) {
- if (idx >= 0)
- goto nextLine;
- goto nextVar;
- }
- QChar c = chars[lineLen - 1];
- if (c != QLatin1Char(' ') && c != QLatin1Char('\t'))
- break;
- lineLen--;
- }
- {
- int contCol = -1;
- if (chars[lineLen - 1] == QLatin1Char('\\'))
- contCol = --lineLen;
- int colNo = 0;
- if (first) {
- colNo = line.indexOf(QLatin1Char('=')) + 1;
- first = false;
- saved = true;
- }
- while (colNo < lineLen) {
- QChar c = chars[colNo];
- if (c == QLatin1Char(' ') || c == QLatin1Char('\t')) {
- colNo++;
- continue;
- }
- int varCol = colNo;
- while (colNo < lineLen) {
- QChar c = chars[colNo];
- if (c == QLatin1Char(' ') || c == QLatin1Char('\t'))
- break;
- colNo++;
- }
- QString fn = line.mid(varCol, colNo - varCol);
- if (relativeFilePaths.contains(fn)) {
- notChanged.removeOne(QDir::cleanPath(proFileDir.absoluteFilePath(fn)));
- if (colNo < lineLen)
- colNo++;
- else if (varCol)
- varCol--;
- int len = colNo - varCol;
- colNo = varCol;
- line.remove(varCol, len);
- lineLen -= len;
- contCol -= len;
- idx -= len;
- if (idx >= 0)
- line.insert(idx, QLatin1String("# ") + fn + QLatin1Char(' '));
- killed = true;
- } else {
- saved = true;
- }
- }
- if (saved) {
- // Entries remained
- contPos.clear();
- } else if (killed) {
- // Entries existed, but were all removed
- if (contCol < 0) {
- // This is the last line, so clear continuations leading to it
- foreach (const ContPos &pos, contPos) {
- QString &bline = (*lines)[pos.first];
- bline.remove(pos.second, 1);
- if (pos.second == bline.length())
- while (bline.endsWith(QLatin1Char(' '))
- || bline.endsWith(QLatin1Char('\t')))
- bline.chop(1);
- }
- contPos.clear();
- }
- if (idx < 0) {
- // Not even a comment stayed behind, so zap the line
- lines->removeAt(lineNo);
- delta++;
- continue;
- }
- }
- if (contCol >= 0)
- contPos.append(qMakePair(lineNo, contCol));
- }
- nextLine:
- lineNo++;
- }
- nextVar: ;
- }
+ foreach (int ln, varLines) {
+ bool first = true;
+ int lineNo = ln - delta;
+ typedef QPair<int, int> ContPos;
+ QList<ContPos> contPos;
+ while (lineNo < lines->count()) {
+ QString &line = (*lines)[lineNo];
+ int lineLen = line.length();
+ bool killed = false;
+ bool saved = false;
+ int idx = line.indexOf(QLatin1Char('#'));
+ if (idx >= 0)
+ lineLen = idx;
+ QChar *chars = line.data();
+ forever {
+ if (!lineLen) {
+ if (idx >= 0)
+ goto nextLine;
+ goto nextVar;
+ }
+ QChar c = chars[lineLen - 1];
+ if (c != QLatin1Char(' ') && c != QLatin1Char('\t'))
+ break;
+ lineLen--;
+ }
+ {
+ int contCol = -1;
+ if (chars[lineLen - 1] == QLatin1Char('\\'))
+ contCol = --lineLen;
+ int colNo = 0;
+ if (first) {
+ colNo = line.indexOf(QLatin1Char('=')) + 1;
+ first = false;
+ saved = true;
+ }
+ while (colNo < lineLen) {
+ QChar c = chars[colNo];
+ if (c == QLatin1Char(' ') || c == QLatin1Char('\t')) {
+ colNo++;
+ continue;
+ }
+ int varCol = colNo;
+ while (colNo < lineLen) {
+ QChar c = chars[colNo];
+ if (c == QLatin1Char(' ') || c == QLatin1Char('\t'))
+ break;
+ colNo++;
+ }
+ const QString fn = line.mid(varCol, colNo - varCol);
+ const int pos = valuesToFind.indexOf(fn);
+ if (pos != -1) {
+ notChanged.removeOne(values.at(pos));
+ if (colNo < lineLen)
+ colNo++;
+ else if (varCol)
+ varCol--;
+ int len = colNo - varCol;
+ colNo = varCol;
+ line.remove(varCol, len);
+ lineLen -= len;
+ contCol -= len;
+ idx -= len;
+ if (idx >= 0)
+ line.insert(idx, QLatin1String("# ") + fn + QLatin1Char(' '));
+ killed = true;
+ } else {
+ saved = true;
+ }
+ }
+ if (saved) {
+ // Entries remained
+ contPos.clear();
+ } else if (killed) {
+ // Entries existed, but were all removed
+ if (contCol < 0) {
+ // This is the last line, so clear continuations leading to it
+ foreach (const ContPos &pos, contPos) {
+ QString &bline = (*lines)[pos.first];
+ bline.remove(pos.second, 1);
+ if (pos.second == bline.length())
+ while (bline.endsWith(QLatin1Char(' '))
+ || bline.endsWith(QLatin1Char('\t')))
+ bline.chop(1);
+ }
+ contPos.clear();
+ }
+ if (idx < 0) {
+ // Not even a comment stayed behind, so zap the line
+ lines->removeAt(lineNo);
+ delta++;
+ continue;
+ }
+ }
+ if (contCol >= 0)
+ contPos.append(qMakePair(lineNo, contCol));
+ }
+ nextLine:
+ lineNo++;
+ }
+ nextVar: ;
}
return notChanged;
}
{
public:
static void addFiles(ProFile *profile, QStringList *lines,
- const QDir &proFileDir, const QStringList &filePaths,
- const QString &var);
+ const QDir &proFileDir, const QStringList &filePaths, const QString &var)
+ {
+ addVarValues(profile, lines, proFileDir, filePaths, var, true);
+ }
+
static QStringList removeFiles(ProFile *profile, QStringList *lines,
- const QDir &proFileDir, const QStringList &filePaths,
- const QStringList &vars);
+ const QDir &proFileDir, const QStringList &filePaths,
+ const QStringList &vars)
+ {
+ return removeVarValues(profile, lines, proFileDir, filePaths, vars, true);
+ }
+
+ static void addVarValues(ProFile *profile, QStringList *lines,
+ const QDir &proFileDir, const QStringList &values, const QString &var)
+ {
+ addVarValues(profile, lines, proFileDir, values, var, false);
+ }
+
+ static QStringList removeVarValues(ProFile *profile, QStringList *lines,
+ const QDir &proFileDir, const QStringList &values,
+ const QStringList &vars)
+ {
+ return removeVarValues(profile, lines, proFileDir, values, vars, false);
+ }
+
+private:
+
+ static void addVarValues(ProFile *profile, QStringList *lines,
+ const QDir &proFileDir, const QStringList &values, const QString &var,
+ bool valuesAreFiles);
+
+ static QStringList removeVarValues(ProFile *profile, QStringList *lines,
+ const QDir &proFileDir, const QStringList &values,
+ const QStringList &vars, bool valuesAreFiles);
};
} // namespace Internal
/* Required headers for select() according to POSIX.1-2001 */
# include <sys/select.h>
/* Required headers for select() according to earlier standards:
- #include <sys/time.h>
- #include <sys/types.h>
- #include <unistd.h>
+# include <sys/time.h>
+# include <sys/types.h>
+# include <unistd.h>
*/
#endif
--- /dev/null
+TEMPLATE = subdirs
+SUBDIRS += qmldump
#include <QDebug>
#include <iostream>
#include <QtDeclarative>
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/private/qmetaobject_p.h>
#include <QtDeclarative/private/qdeclarativemetatype_p.h>
+#include <QtDeclarative/private/qdeclarativeopenmetaobject_p.h>
#include <QtDeclarative/QDeclarativeView>
static QHash<QByteArray, const QDeclarativeType *> qmlTypeByCppName;
if (! meta || metas->contains(meta))
return;
- metas->insert(meta);
+ // dynamic meta objects break things badly
+ const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate *>(meta->d.data);
+ if (!(mop->flags & DynamicMetaObject))
+ metas->insert(meta);
+
processMetaObject(meta->superClass(), metas);
}
void dump(const QMetaObject *meta, QXmlStreamWriter *xml)
{
+ QByteArray qmlTypeName = convertToQmlType(meta->className());
+
xml->writeStartElement("type");
QXmlStreamAttributes attributes;
- attributes.append(QXmlStreamAttribute("name", convertToQmlType(meta->className())));
+ attributes.append(QXmlStreamAttribute("name", qmlTypeName));
if (const QDeclarativeType *qmlTy = qmlTypeByCppName.value(meta->className())) {
attributes.append(QXmlStreamAttribute("version", QString("%1.%2").arg(qmlTy->majorVersion()).arg(qmlTy->minorVersion())));
xml->writeEndElement();
}
-void writeScriptElement(QXmlStreamWriter *xml)
+void writeEasingCurve(QXmlStreamWriter *xml)
{
xml->writeStartElement("type");
{
QXmlStreamAttributes attributes;
- attributes.append(QXmlStreamAttribute("name", "Script"));
- xml->writeAttributes(attributes);
- }
-
- xml->writeStartElement("property");
- {
- QXmlStreamAttributes attributes;
- attributes.append(QXmlStreamAttribute("name", "script"));
- attributes.append(QXmlStreamAttribute("type", "string"));
- xml->writeAttributes(attributes);
- }
- xml->writeEndElement();
-
- xml->writeStartElement("property");
- {
- QXmlStreamAttributes attributes;
- attributes.append(QXmlStreamAttribute("name", "source"));
- attributes.append(QXmlStreamAttribute("type", "QUrl"));
+ attributes.append(QXmlStreamAttribute("name", "QEasingCurve"));
+ attributes.append(QXmlStreamAttribute("extends", "Qt.Easing"));
xml->writeAttributes(attributes);
}
- xml->writeEndElement();
xml->writeEndElement();
}
{
QApplication app(argc, argv);
+ if (argc != 1 && argc != 2) {
+ qWarning() << "Usage: qmldump [path/to/plugin/directory]";
+ return 1;
+ }
+
+ QString pluginImportName;
+ QString pluginImportPath;
+ if (argc == 2) {
+ QFileInfo pluginPath(argv[1]);
+ if (pluginPath.exists() && pluginPath.isDir()) {
+ pluginImportPath = pluginPath.absolutePath();
+ pluginImportName = pluginPath.fileName();
+ }
+ }
+
QDeclarativeView view;
QDeclarativeEngine *engine = view.engine();
+ if (!pluginImportPath.isEmpty())
+ engine->addImportPath(pluginImportPath);
+
+ QByteArray importCode;
+ importCode += "import Qt 4.7;\n";
+ importCode += "import Qt.labs.particles 4.7;\n";
+ importCode += "import Qt.labs.gestures 4.7;\n";
+ importCode += "import Qt.labs.folderlistmodel 4.7;\n";
+ importCode += "import org.webkit 1.0;\n";
+ if (!pluginImportName.isEmpty())
+ importCode += QString("import %0 1.0;\n").arg(pluginImportName).toAscii();
{
- QByteArray code;
- code += "import Qt 4.7;\n";
- code += "import Qt.labs.particles 4.7;\n";
- code += "import Qt.labs.gestures 4.7;\n";
- code += "import Qt.labs.folderlistmodel 4.7;\n";
- code += "import org.webkit 1.0;\n";
+ QByteArray code = importCode;
code += "Item {}";
QDeclarativeComponent c(engine);
+
c.setData(code, QUrl("xxx"));
c.create();
+ if (!c.errors().isEmpty())
+ qDebug() << c.errorString();
}
cppToQml.insert("QString", "string");
- cppToQml.insert("QEasingCurve", "Qt.Easing");
cppToQml.insert("QDeclarativeEasingValueType::Type", "Type");
QSet<const QMetaObject *> metas;
metas.insert(FriendlyQObject::qtMeta());
- // ### TODO: We don't treat extended types correctly. Currently only hits the
- // QDeclarativeGraphicsWidget extension to QGraphicsWidget
+ QMultiHash<QByteArray, QByteArray> extensions;
foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
- if (ty->isExtendedType())
- continue;
-
- cppToQml.insert(ty->metaObject()->className(), ty->qmlTypeName());
qmlTypeByCppName.insert(ty->metaObject()->className(), ty);
+ if (ty->isExtendedType()) {
+ extensions.insert(ty->typeName(), ty->metaObject()->className());
+ } else {
+ cppToQml.insert(ty->metaObject()->className(), ty->qmlTypeName());
+ }
processDeclarativeType(ty, &metas);
}
+ // Adjust qml names of extended objects.
+ // The chain ends up being:
+ // __extended__.originalname - the base object
+ // __extension_0_.originalname - first extension
+ // ..
+ // __extension_n-2_.originalname - second to last extension
+ // originalname - last extension
+ foreach (const QByteArray &extendedCpp, extensions.keys()) {
+ const QByteArray extendedQml = cppToQml.value(extendedCpp);
+ cppToQml.insert(extendedCpp, "__extended__." + extendedQml);
+ QList<QByteArray> extensionCppNames = extensions.values(extendedCpp);
+ for (int i = 0; i < extensionCppNames.size() - 1; ++i) {
+ QByteArray adjustedName = QString("__extension__%1.%2").arg(QString::number(i), QString(extendedQml)).toAscii();
+ cppToQml.insert(extensionCppNames.value(i), adjustedName);
+ }
+ cppToQml.insert(extensionCppNames.last(), extendedQml);
+ }
+
foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
if (ty->isExtendedType())
continue;
QByteArray tyName = ty->qmlTypeName();
tyName = tyName.mid(tyName.lastIndexOf('/') + 1);
- QByteArray code;
- code += "import Qt 4.7;\n";
- code += "import Qt.labs.particles 4.7;\n";
- code += "import Qt.labs.gestures 4.7;\n";
- code += "import Qt.labs.folderlistmodel 4.7;\n";
- code += "import org.webkit 1.0;\n";
+ QByteArray code = importCode;
code += tyName;
code += " {}\n";
QDeclarativeComponent c(engine);
c.setData(code, QUrl("xxx"));
- processObject(c.create(), &metas);
+
+ QObject *object = c.create();
+ if (object)
+ processObject(object, &metas);
+ else
+ qDebug() << "Could not create" << tyName << ":" << c.errorString();
}
QByteArray bytes;
dump(meta, &xml);
}
- writeScriptElement(&xml);
+ // define QEasingCurve as an extension of Qt.Easing
+ writeEasingCurve(&xml);
xml.writeEndElement();
xml.writeEndDocument();
TEMPLATE = app
SOURCES += main.cpp
+
+include(../../../../qtcreator.pri)
+include(../../../private_headers.pri)
+DESTDIR = $$IDE_BIN_PATH
+include(../../../rpath.pri)
bool result = true;
static const char *filesToPatch[] = {
- #ifdef Q_OS_WIN
+# ifdef Q_OS_WIN
"/bin/qmake.exe",
"/bin/QtCore4.dll",
"/bin/QtCored4.dll",
"/lib/QtCored4.dll"
- #else
+# else
"/bin/qmake",
"/lib/libQtCore.so",
- #endif
+# endif
};
for (int i = 0; i < (int)(sizeof(filesToPatch) / sizeof(filesToPatch[0])); i++) {
TEMPLATE = subdirs
win32:SUBDIRS = qtcdebugger
+SUBDIRS += qml
# profilereader \
aggregation \
changeset \
- icheckbuild
+ icheckbuild \
+ generichighlighter
contains (QT_CONFIG, declarative) {
SUBDIRS += qml
Snapshot snapshot;
snapshot.insert(doc);
- Document::Ptr emptyDoc = Document::create("<empty>");
-
Class *baseClass = doc->globalSymbolAt(0)->asClass();
QVERIFY(baseClass);
Class *derivedClass = doc->globalSymbolAt(1)->asClass();
QVERIFY(derivedClass);
- LookupContext ctx(derivedClass, emptyDoc, doc, snapshot);
+ const LookupContext ctx(doc, snapshot);
- const QList<Symbol *> candidates =
- ctx.resolveClass(derivedClass->baseClassAt(0)->name());
+ ClassOrNamespace *klass = ctx.lookupType(derivedClass->baseClassAt(0)->name(), derivedClass->scope());
+ QVERIFY(klass != 0);
- QCOMPARE(candidates.size(), 1);
- QCOMPARE(candidates.at(0), baseClass);
+ QCOMPARE(klass->symbols().size(), 1);
+ QCOMPARE(klass->symbols().first(), baseClass);
TranslationUnit *unit = doc->translationUnit();
QVERIFY(unit != 0);
Snapshot snapshot;
snapshot.insert(doc);
- Document::Ptr emptyDoc = Document::create("<empty>");
-
ObjCClass *iface = doc->globalSymbolAt(0)->asObjCClass();
QVERIFY(iface);
QVERIFY(iface->isInterface());
QVERIFY(!impl->isInterface());
QCOMPARE(impl->memberCount(), 3U);
- ObjCMethod *allocMethod = impl->memberAt(0)->asObjCMethod();
- QVERIFY(allocMethod);
- QVERIFY(allocMethod->name() && allocMethod->name()->identifier());
- QCOMPARE(QLatin1String(allocMethod->name()->identifier()->chars()), QLatin1String("alloc"));
+ Declaration *allocMethodIface = iface->memberAt(0)->asDeclaration();
+ QVERIFY(allocMethodIface);
+ QVERIFY(allocMethodIface->name() && allocMethodIface->name()->identifier());
+ QCOMPARE(QLatin1String(allocMethodIface->name()->identifier()->chars()), QLatin1String("alloc"));
+
+ ObjCMethod *allocMethodImpl = impl->memberAt(0)->asObjCMethod();
+ QVERIFY(allocMethodImpl);
+ QVERIFY(allocMethodImpl->name() && allocMethodImpl->name()->identifier());
+ QCOMPARE(QLatin1String(allocMethodImpl->name()->identifier()->chars()), QLatin1String("alloc"));
ObjCMethod *deallocMethod = impl->memberAt(2)->asObjCMethod();
QVERIFY(deallocMethod);
QVERIFY(deallocMethod->name() && deallocMethod->name()->identifier());
QCOMPARE(QLatin1String(deallocMethod->name()->identifier()->chars()), QLatin1String("dealloc"));
- const LookupContext ctxt(impl, emptyDoc, doc, snapshot);
+ const LookupContext context(doc, snapshot);
// check class resolving:
- const QList<Symbol *> candidates = ctxt.resolveObjCClass(impl->name());
- QCOMPARE(candidates.size(), 2);
- QVERIFY(candidates.contains(iface));
- QVERIFY(candidates.contains(impl));
-
- // check scope expansion:
- QList<Scope *> expandedScopes;
- ctxt.expand(impl->members(), ctxt.visibleScopes(), &expandedScopes);
- QCOMPARE(expandedScopes.size(), 2);
-
- const ResolveExpression resolver(ctxt);
+ ClassOrNamespace *klass = context.lookupType(impl->name(), impl->scope());
+ QVERIFY(klass != 0);
+ QCOMPARE(klass->symbols().size(), 2);
+ QVERIFY(klass->symbols().contains(iface));
+ QVERIFY(klass->symbols().contains(impl));
// check method resolving:
- QList<LookupItem> results = resolver.resolveMember(allocMethod->name(), impl);
+ QList<Symbol *> results = context.lookup(allocMethodImpl->name(), impl->members());
QCOMPARE(results.size(), 2);
- QVERIFY(results.at(0).lastVisibleSymbol() == allocMethod || results.at(1).lastVisibleSymbol() == allocMethod);
- QVERIFY(results.at(0).lastVisibleSymbol()->asDeclaration() || results.at(1).lastVisibleSymbol()->asDeclaration());
+ QCOMPARE(results.at(0), allocMethodIface);
+ QCOMPARE(results.at(1), allocMethodImpl);
- results = resolver.resolveMember(deallocMethod->name(), impl);
+ results = context.lookup(deallocMethod->name(), impl->members());
QCOMPARE(results.size(), 1);
- QCOMPARE(results.at(0).lastVisibleSymbol(), deallocMethod);
+ QCOMPARE(results.at(0), deallocMethod);
}
void tst_Lookup::class_with_baseclass()
QVERIFY(baseMethod->name() && baseMethod->name()->identifier());
QCOMPARE(QLatin1String(baseMethod->name()->identifier()->chars()), QLatin1String("baseMethod"));
- const LookupContext ctxt(zooImpl, emptyDoc, doc, snapshot);
-
- const QList<Symbol *> candidates = ctxt.resolveObjCClass(baseZoo->name());
- QCOMPARE(candidates.size(), 1);
- QVERIFY(candidates.contains(baseZoo));
-
- QList<Scope *> expandedScopes;
- ctxt.expand(zooImpl->members(), ctxt.visibleScopes(), &expandedScopes);
- QCOMPARE(expandedScopes.size(), 3);
+ const LookupContext context(doc, snapshot);
- const ResolveExpression resolver(ctxt);
+ ClassOrNamespace *objClass = context.lookupType(baseZoo->name(), zooImpl->scope());
+ QVERIFY(objClass != 0);
+ QVERIFY(objClass->symbols().contains(baseZoo));
- QList<LookupItem> results = resolver.resolveMember(baseDecl->name(), zooImpl);
+ QList<Symbol *> results = context.lookup(baseDecl->name(), zooImpl->members());
QCOMPARE(results.size(), 1);
- QCOMPARE(results.at(0).lastVisibleSymbol(), baseDecl);
+ QCOMPARE(results.at(0), baseDecl);
- results = resolver.resolveMember(baseMethod->name(), zooImpl);
+ results = context.lookup(baseMethod->name(), zooImpl->members());
QCOMPARE(results.size(), 1);
- QCOMPARE(results.at(0).lastVisibleSymbol(), baseMethod);
+ QCOMPARE(results.at(0), baseMethod);
}
void tst_Lookup::class_with_protocol_with_protocol()
Snapshot snapshot;
snapshot.insert(doc);
- Document::Ptr emptyDoc = Document::create("<empty>");
-
ObjCProtocol *P1 = doc->globalSymbolAt(0)->asObjCProtocol();
QVERIFY(P1);
QCOMPARE(P1->memberCount(), 1U);
ObjCClass *zooImpl = doc->globalSymbolAt(3)->asObjCClass();
QVERIFY(zooImpl);
- const LookupContext ctxt(zooImpl, emptyDoc, doc, snapshot);
+ const LookupContext context(doc, snapshot);
{
- const QList<Symbol *> candidates = ctxt.resolveObjCProtocol(P1->name());
+ const QList<Symbol *> candidates = context.lookup(P1->name(), zooImpl->scope());
QCOMPARE(candidates.size(), 1);
QVERIFY(candidates.contains(P1));
}
{
- const QList<Symbol *> candidates = ctxt.resolveObjCProtocol(P2->protocolAt(0)->name());
+ const QList<Symbol *> candidates = context.lookup(P2->protocolAt(0)->name(), zooImpl->scope());
QCOMPARE(candidates.size(), 1);
QVERIFY(candidates.contains(P1));
}
- QList<Scope *> expandedScopes;
- ctxt.expand(zooImpl->members(), ctxt.visibleScopes(), &expandedScopes);
- QCOMPARE(expandedScopes.size(), 4);
-
- const ResolveExpression resolver(ctxt);
-
- QList<LookupItem> results = resolver.resolveMember(p1method->name(), zooImpl);
+ QList<Symbol *> results = context.lookup(p1method->name(), zooImpl->members());
QCOMPARE(results.size(), 1);
- QCOMPARE(results.at(0).lastVisibleSymbol(), p1method);
+ QCOMPARE(results.at(0), p1method);
}
void tst_Lookup::iface_impl_scoping()
Snapshot snapshot;
snapshot.insert(doc);
- Document::Ptr emptyDoc = Document::create("<empty>");
ObjCClass *iface = doc->globalSymbolAt(0)->asObjCClass();
QVERIFY(iface);
QVERIFY(iface->isInterface());
Block *method1Body = method1Impl->memberAt(0)->asBlock();
QVERIFY(method1Body);
- const LookupContext ctxt(method1Body, emptyDoc, doc, snapshot);
+ const LookupContext context(doc, snapshot);
{ // verify if we can resolve "arg" in the body
QCOMPARE(method1Impl->argumentCount(), 1U);
QVERIFY(arg->name()->identifier());
QCOMPARE(arg->name()->identifier()->chars(), "arg");
- const QList<Symbol *> candidates = ctxt.resolve(arg->name());
+ const QList<Symbol *> candidates = context.lookup(arg->name(), method1Body->scope());
QCOMPARE(candidates.size(), 1);
QVERIFY(candidates.at(0)->type()->asIntegerType());
}
QCOMPARE(method2->identifier()->chars(), "method2");
{ // verify if we can resolve "method2" in the body
- const QList<Symbol *> candidates = ctxt.resolve(method2->name());
+ const QList<Symbol *> candidates = context.lookup(method2->name(), method1Body->scope());
QCOMPARE(candidates.size(), 1);
QCOMPARE(candidates.at(0), method2);
}
-
- { // now let's see if the resolver can do the same for method2
- const ResolveExpression resolver(ctxt);
-
- const QList<LookupItem> results = resolver.resolveMember(method2->name(),
- impl);
- QCOMPARE(results.size(), 1);
- QCOMPARE(results.at(0).lastVisibleSymbol(), method2);
- }
}
QTEST_APPLESS_MAIN(tst_Lookup)
#include <Names.h>
#include <Literals.h>
#include <DiagnosticClient.h>
-#include <GenTemplateInstance.h>
+#include <DeprecatedGenTemplateInstance.h>
#include <Overview.h>
#include <ExpressionUnderCursor.h>
#include <Names.h>
void tst_Semantic::template_instance_1()
{
- QSharedPointer<Document> doc = document("void append(const _Tp &value);");
+ QSharedPointer<Document> doc = document("template <typename _Tp> class QList { void append(const _Tp &value); };");
QCOMPARE(doc->errorCount, 0U);
QCOMPARE(doc->globals->symbolCount(), 1U);
- Declaration *decl = doc->globals->symbolAt(0)->asDeclaration();
+ Declaration *decl = doc->globals->symbolAt(0)->asClass()->memberAt(0)->asDeclaration();
QVERIFY(decl);
- GenTemplateInstance::Substitution subst;
- const Identifier *nameTp = control.findOrInsertIdentifier("_Tp");
- FullySpecifiedType intTy(control.integerType(IntegerType::Int));
- subst.append(qMakePair(nameTp, intTy));
+ FullySpecifiedType templArgs[] = { control.integerType(IntegerType::Int) };
+ const Name *templId = control.templateNameId(control.findOrInsertIdentifier("QList"), templArgs, 1);
- GenTemplateInstance inst(&control, subst);
- FullySpecifiedType genTy = inst(decl);
+ FullySpecifiedType genTy = DeprecatedGenTemplateInstance::instantiate(templId, decl, &control);
Overview oo;
oo.setShowReturnTypes(true);
const QString genDecl = oo.prettyType(genTy);
- QCOMPARE(genDecl, QString::fromLatin1("void(const int &)"));
+ QCOMPARE(genDecl, QString::fromLatin1("void (const int &)"));
}
void tst_Semantic::expression_under_cursor_1()
SOURCES += \
$$DEBUGGERDIR/gdb/gdbmi.cpp \
+ $$DEBUGGERDIR/tcf/json.cpp \
$$MACROSDIR/gdbmacros.cpp \
tst_dumpers.cpp \
#undef private
#include "gdb/gdbmi.h"
+#include "tcf/json.h"
#include "gdbmacros.h"
#include "gdbmacros_p.h"
"numchild=\"0\"}]";
+static const char jsont1[] =
+ "{\"Size\":100564,\"UID\":0,\"GID\":0,\"Permissions\":33261,"
+ "\"ATime\":1242370878000,\"MTime\":1239154689000}";
+
struct Int3 {
Int3() { i1 = 42; i2 = 43; i3 = 44; }
int i1, i2, i3;
'\n' + QString(input));
}
+ void testJson(const char* input)
+ {
+ QCOMPARE('\n' + QString::fromLatin1(JsonValue(input).toString(false)),
+ '\n' + QString(input));
+ }
+
private slots:
void mi1() { testMi(gdbmi1); }
void mi2() { testMi(gdbmi2); }
void mi11() { testMi(gdbmi11); }
//void mi12() { testMi(gdbmi12); }
+ void json1() { testJson(jsont1); }
+
void infoBreak();
void niceType();
void niceType_data();
dumpQLinkedListHelper(l3);
}
- #if 0
+# if 0
void tst_Debugger::dumpQLinkedList()
{
// Case 1: Simple element type.
//dumpQLinkedListHelper(l3);
testDumper("", &l, NS"QLinkedList", true, NS"QString");
}
- #endif
+# endif
void tst_Debugger::dumpQList_int()
{
vec.push_back("Hallo2");
std::set<std::string> stdSet;
stdSet.insert("s1");
- #ifdef QT_GUI_LIB
+# ifdef QT_GUI_LIB
QWidget *ww = 0; //this;
QWidget &wwr = *ww;
Q_UNUSED(wwr);
- #endif
+# endif
QSharedPointer<QString> sps(new QString("hallo"));
QList<QSharedPointer<QString> > spsl;
QLinkedList<QString> lls;
lls << "link1" << "link2";
- #ifdef QT_GUI_LIB
+# ifdef QT_GUI_LIB
QStandardItemModel *model = new QStandardItemModel;
model->appendRow(new QStandardItem("i1"));
- #endif
+# endif
QList <QList<int> > nestedIntList;
nestedIntList << QList<int>();
void dump_QAbstractItemModel()
{
- #ifdef QT_GUI_LIB
+# ifdef QT_GUI_LIB
/* A */ QStringList strList;
strList << "String 1";
QStringListModel model1(strList);
/* E */ model2.appendRow(QList<QStandardItem *>() << (new QStandardItem("Item (0,0)")) << (new QStandardItem("Item (0,1)")));
/* F */ model2.appendRow(QList<QStandardItem *>() << (new QStandardItem("Item (1,0)")) << (new QStandardItem("Item (1,1)")));
/* G */ (void) (model1.rowCount() + model2.rowCount() + strList.size());
- #endif
+# endif
}
void tst_Gdb::dump_QAbstractItemModel()
{
- #ifdef QT_GUI_LIB
+# ifdef QT_GUI_LIB
/* A */ QStringList strList;
QString template_ =
"{iname='local.strList',name='strList',type='"NS"QStringList',"
check("A", template_.arg("1").toAscii());
next(4);
check("B", template_.arg("1").toAscii());
- #endif
+# endif
}
void dump_QDateTime()
{
- #ifndef QT_NO_DATESTRING
+# ifndef QT_NO_DATESTRING
/* A */ QDateTime d;
/* B */ d = QDateTime::fromString("M5d21y7110:31:02", "'M'M'd'd'y'yyhh:mm:ss");
/* C */ (void) d.isNull();
- #endif
+# endif
}
void tst_Gdb::dump_QDateTime()
{
- #ifndef QT_NO_DATESTRING
+# ifndef QT_NO_DATESTRING
prepare("dump_QDateTime");
if (checkUninitialized)
check("A","{iname='local.d',name='d',"
"value='-',numchild='3'}"
"]}",
"local.d");
- #endif
+# endif
}
void dump_QImage()
{
- #ifdef QT_GUI_LIB
+# ifdef QT_GUI_LIB
/* A */ QImage image; // Null image.
/* B */ image = QImage(30, 700, QImage::Format_RGB555); // Normal image.
/* C */ image = QImage(100, 0, QImage::Format_Invalid); // Invalid image.
/* D */ (void) image.size();
/* E */ (void) image.size();
- #endif
+# endif
}
void tst_Gdb::dump_QImage()
{
- #ifdef QT_GUI_LIB
+# ifdef QT_GUI_LIB
prepare("dump_QImage");
next();
check("B", "{iname='local.image',name='image',type='"NS"QImage',"
// FIXME:
//check("E", "{iname='local.image',name='image',type='"NS"QImage',"
// "value='(100x0)',numchild='0'}");
- #endif
+# endif
}
#if 0
void dump_QPixmap()
{
- #ifdef QT_GUI_LIB
+# ifdef QT_GUI_LIB
/* A */ QPixmap p; // Case 1: Null Pixmap.
/* B */ p = QPixmap(20, 100); // Case 2: Uninitialized non-null pixmap.
/* C */ p = QPixmap(pixmap); // Case 3: Initialized non-null pixmap.
/* D */ (void) p.size();
- #endif
+# endif
}
void tst_Gdb::dump_QPixmap()
{
- #ifdef QT_GUI_LIB
+# ifdef QT_GUI_LIB
prepare("dump_QPixmap");
next();
check("B", "{iname='local.p',name='p',type='"NS"QPixmap',"
next();
check("D", "{iname='local.p',name='p',type='"NS"QPixmap',"
"value='(2x24)',numchild='0'}");
- #endif
+# endif
}
void tst_Gdb::dump_QVariant()
{
- #define PRE "iname='local.v',name='v',type='"NS"QVariant',"
+# define PRE "iname='local.v',name='v',type='"NS"QVariant',"
prepare("dump_QVariant");
if (checkUninitialized) /*<invalid>*/
check("A","{"PRE"'value=<invalid>',numchild='0'}");
void dump_QWidget()
{
- #ifdef QT_GUI_LIB
+# ifdef QT_GUI_LIB
/* A */ QWidget w;
/* B */ (void) w.size();
- #endif
+# endif
}
void tst_Gdb::dump_QWidget()
{
- #ifdef QT_GUI_LIB
+# ifdef QT_GUI_LIB
prepare("dump_QWidget");
if (checkUninitialized)
check("A","{iname='local.w',name='w',"
"{name='data',type='"NS"QWidgetData *',"
"value='-',numchild='1'}]}",
"local.w,local.w."NS"QObject");
- #endif
+# endif
}
int main(int argc, char *argv[])
{
- #ifdef QT_GUI_LIB
+# ifdef QT_GUI_LIB
QApplication app(argc, argv);
- #else
+# else
QCoreApplication app(argc, argv);
- #endif
+# endif
breaker();
if (argc == 2 && QByteArray(argv[1]) == "run") {
QTest::newRow("Apple")
<< "GNU gdb 6.3.50-20050815 (Apple version gdb-1461.2)"
<< 60350 << 1461 << true;
+
+ QTest::newRow("Apple")
+ << "GNU gdb 6.3.50-20050815 (Apple version gdb-960)"
+ << 60350 << 960 << true;
}
--- /dev/null
+TEMPLATE = subdirs
+SUBDIRS += specificrules highlighterengine
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef BASETEXTDOCUMENTLAYOUT_H
+#define BASETEXTDOCUMENTLAYOUT_H
+
+/*
+ Since the text editor plugin directory is not included in the search list of the pro file, this
+ file replaces the "real" basetextdocumentlayout.h file. The objective is to simply use
+ QTextBlockUserData instead of TextEditor::TextBlockUserData to avoid "external"
+ dependencies or intrusive defines.
+ */
+
+#include <QtGui/QTextBlockUserData>
+
+typedef QTextBlockUserData TextBlockUserData;
+
+#endif // BASETEXTDOCUMENTLAYOUT_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "formats.h"
+
+#include <QtCore/Qt>
+
+Formats::Formats()
+{
+ m_keywordFormat.setForeground(Qt::darkGray);
+ m_dataTypeFormat.setForeground(Qt::gray);
+ m_decimalFormat.setForeground(Qt::lightGray);
+ m_baseNFormat.setForeground(Qt::red);
+ m_floatFormat.setForeground(Qt::green);
+ m_charFormat.setForeground(Qt::blue);
+ m_stringFormat.setForeground(Qt::cyan);
+ m_commentFormat.setForeground(Qt::magenta);
+ m_alertFormat.setForeground(Qt::yellow);
+ m_errorFormat.setForeground(Qt::darkRed);
+ m_functionFormat.setForeground(Qt::darkGreen);
+ m_regionMarkerFormat.setForeground(Qt::darkBlue);
+ m_othersFormat.setForeground(Qt::darkCyan);
+}
+
+Formats &Formats::instance()
+{
+ static Formats formats;
+ return formats;
+}
+
+QString Formats::name(const QTextCharFormat &format) const
+{
+ if (format == QTextCharFormat())
+ return "Default format";
+ else if (format == m_keywordFormat)
+ return "Keyword";
+ else if (format == m_dataTypeFormat)
+ return "Data type format";
+ else if (format == m_decimalFormat)
+ return "Decimal format";
+ else if (format == m_baseNFormat)
+ return "Base N format";
+ else if (format == m_floatFormat)
+ return "Float format";
+ else if (format == m_charFormat)
+ return "Char format";
+ else if (format == m_stringFormat)
+ return "String format";
+ else if (format == m_commentFormat)
+ return "Comment format";
+ else if (format == m_alertFormat)
+ return "Alert format";
+ else if (format == m_errorFormat)
+ return "Error format";
+ else if (format == m_functionFormat)
+ return "Function format";
+ else if (format == m_regionMarkerFormat)
+ return "Region Marker format";
+ else if (format == m_othersFormat)
+ return "Others format";
+ else
+ return "Unidentified format";
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef FORMATS_H
+#define FORMATS_H
+
+#include <QtGui/QTextCharFormat>
+
+class Formats
+{
+public:
+ static Formats &instance();
+
+ const QTextCharFormat &keywordFormat() const { return m_keywordFormat; }
+ const QTextCharFormat &dataTypeFormat() const { return m_dataTypeFormat; }
+ const QTextCharFormat &decimalFormat() const { return m_decimalFormat; }
+ const QTextCharFormat &baseNFormat() const { return m_baseNFormat; }
+ const QTextCharFormat &floatFormat() const { return m_floatFormat; }
+ const QTextCharFormat &charFormat() const { return m_charFormat; }
+ const QTextCharFormat &stringFormat() const { return m_stringFormat; }
+ const QTextCharFormat &commentFormat() const { return m_commentFormat; }
+ const QTextCharFormat &alertFormat() const { return m_alertFormat; }
+ const QTextCharFormat &errorFormat() const { return m_errorFormat; }
+ const QTextCharFormat &functionFormat() const { return m_functionFormat; }
+ const QTextCharFormat ®ionMarketFormat() const { return m_regionMarkerFormat; }
+ const QTextCharFormat &othersFormat() const { return m_othersFormat; }
+
+ QString name(const QTextCharFormat &format) const;
+
+private:
+ Formats();
+ Q_DISABLE_COPY(Formats);
+
+ QTextCharFormat m_keywordFormat;
+ QTextCharFormat m_dataTypeFormat;
+ QTextCharFormat m_decimalFormat;
+ QTextCharFormat m_baseNFormat;
+ QTextCharFormat m_floatFormat;
+ QTextCharFormat m_charFormat;
+ QTextCharFormat m_stringFormat;
+ QTextCharFormat m_commentFormat;
+ QTextCharFormat m_alertFormat;
+ QTextCharFormat m_errorFormat;
+ QTextCharFormat m_functionFormat;
+ QTextCharFormat m_regionMarkerFormat;
+ QTextCharFormat m_othersFormat;
+};
+
+#endif // FORMATS_H
--- /dev/null
+QT += gui testlib
+
+GENERICHIGHLIGHTERDIR = ../../../../src/plugins/texteditor/generichighlighter
+
+SOURCES += tst_highlighterengine.cpp \
+ highlightermock.cpp \
+ $$GENERICHIGHLIGHTERDIR/highlighter.cpp \
+ $$GENERICHIGHLIGHTERDIR/context.cpp \
+ $$GENERICHIGHLIGHTERDIR/dynamicrule.cpp \
+ $$GENERICHIGHLIGHTERDIR/rule.cpp \
+ $$GENERICHIGHLIGHTERDIR/specificrules.cpp \
+ $$GENERICHIGHLIGHTERDIR/progressdata.cpp \
+ $$GENERICHIGHLIGHTERDIR/highlightdefinition.cpp \
+ $$GENERICHIGHLIGHTERDIR/keywordlist.cpp \
+ $$GENERICHIGHLIGHTERDIR/itemdata.cpp \
+ formats.cpp
+
+HEADERS += \
+ highlightermock.h \
+ basetextdocumentlayout.h \
+ formats.h
+
+INCLUDEPATH += $$GENERICHIGHLIGHTERDIR
+
+TARGET=tst_$$TARGET
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlightermock.h"
+#include "context.h"
+#include "highlightdefinition.h"
+#include "formats.h"
+
+#include <QtCore/QDebug>
+#include <QtTest/QtTest>
+
+namespace QTest {
+template<>
+char *toString(const QTextCharFormat &format)
+{
+ QByteArray ba = Formats::instance().name(format).toLatin1();
+ return qstrdup(ba.data());
+}
+}
+
+using namespace TextEditor;
+using namespace Internal;
+
+HighlighterMock::HighlighterMock(const QSharedPointer<Context> &defaultContext,
+ QTextDocument *parent) :
+ Highlighter(defaultContext, parent),
+ m_debugDetails(false),
+ m_statesCounter(0),
+ m_formatsCounter(0),
+ m_noTestCall(false),
+ m_considerEmptyLines(false)
+{}
+
+void HighlighterMock::reset()
+{
+ m_states.clear();
+ m_statesCounter = 0;
+ m_formatSequence.clear();
+ m_formatsCounter = 0;
+ m_debugDetails = false;
+ m_noTestCall = false;
+ m_considerEmptyLines = false;
+}
+
+void HighlighterMock::showDebugDetails()
+{ m_debugDetails = true; }
+
+void HighlighterMock::considerEmptyLines()
+{ m_considerEmptyLines = true; }
+
+void HighlighterMock::startNoTestCalls()
+{ m_noTestCall = true; }
+
+void HighlighterMock::endNoTestCalls()
+{ m_noTestCall = false; }
+
+void HighlighterMock::setExpectedBlockState(const int state)
+{ m_states << state; }
+
+void HighlighterMock::setExpectedBlockStates(const QList<int> &states)
+{ m_states = states; }
+
+void HighlighterMock::setExpectedHighlightSequence(const HighlightSequence &format)
+{ m_formatSequence << format; }
+
+void HighlighterMock::setExpectedHighlightSequences(const QList<HighlightSequence> &formats)
+{ m_formatSequence = formats; }
+
+void HighlighterMock::highlightBlock(const QString &text)
+{
+ Highlighter::highlightBlock(text);
+
+ if (text.isEmpty() && !m_considerEmptyLines)
+ return;
+
+ if (m_noTestCall)
+ return;
+
+ if (m_states.isEmpty() || m_formatSequence.isEmpty())
+ QFAIL("No expected data setup.");
+
+ if (m_debugDetails)
+ qDebug() << "Highlighting" << text;
+
+ if (m_states.size() <= m_statesCounter)
+ QFAIL("Expected state for current block not set.");
+ QCOMPARE(currentBlockState(), m_states.at(m_statesCounter++));
+
+ if (m_formatSequence.size() <= m_formatsCounter)
+ QFAIL("Expected highlight sequence for current block not set.");
+ for (int i = 0; i < text.length(); ++i) {
+ if (text.at(i).isSpace())
+ continue;
+ if (m_debugDetails)
+ qDebug() << "at offset" << i;
+ QCOMPARE(format(i), m_formatSequence.at(m_formatsCounter).m_formats.at(i));
+ }
+ ++m_formatsCounter;
+}
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTERMOCK_H
+#define HIGHLIGHTERMOCK_H
+
+#include "highlighter.h"
+
+#include <QtCore/QList>
+
+namespace TextEditor {
+namespace Internal {
+class Context;
+class HighlightDefinition;
+}
+}
+
+struct HighlightSequence
+{
+ HighlightSequence() {}
+ HighlightSequence(int from, int to, const QTextCharFormat &format = QTextCharFormat())
+ { add(from, to, format); }
+ HighlightSequence(const HighlightSequence &sequence)
+ { m_formats = sequence.m_formats; }
+
+ void add(int from, int to, const QTextCharFormat &format = QTextCharFormat())
+ {
+ for (int i = from; i < to; ++i)
+ m_formats.append(format);
+ }
+
+ QList<QTextCharFormat> m_formats;
+};
+
+class HighlighterMock : public TextEditor::Internal::Highlighter
+{
+public:
+ HighlighterMock(const QSharedPointer<TextEditor::Internal::Context> &defaultContext,
+ QTextDocument *parent = 0);
+
+ void reset();
+ void showDebugDetails();
+ void considerEmptyLines();
+
+ void startNoTestCalls();
+ void endNoTestCalls();
+
+ void setExpectedBlockState(const int state);
+ void setExpectedBlockStates(const QList<int> &states);
+ void setExpectedHighlightSequence(const HighlightSequence &format);
+ void setExpectedHighlightSequences(const QList<HighlightSequence> &formats);
+
+protected:
+ virtual void highlightBlock(const QString &text);
+
+private:
+ QList<int> m_states;
+ int m_statesCounter;
+ QList<HighlightSequence> m_formatSequence;
+ int m_formatsCounter;
+ bool m_debugDetails;
+ bool m_noTestCall;
+ bool m_considerEmptyLines;
+};
+
+#endif // HIGHLIGHTERMOCK_H
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlightdefinition.h"
+#include "keywordlist.h"
+#include "itemdata.h"
+#include "context.h"
+#include "specificrules.h"
+#include "highlightermock.h"
+#include "formats.h"
+
+#include <QtCore/QSharedPointer>
+#include <QtCore/QScopedPointer>
+#include <QtCore/QList>
+#include <QtCore/QMetaType>
+#include <QtGui/QPlainTextEdit>
+#include <QtTest/QtTest>
+
+using namespace TextEditor;
+using namespace Internal;
+
+Q_DECLARE_METATYPE(HighlightSequence)
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QList<HighlightSequence>)
+
+class tst_HighlighterEngine : public QObject
+{
+ Q_OBJECT
+public:
+ tst_HighlighterEngine();
+
+private slots:
+ void initTestCase();
+ void init();
+
+ void testSimpleLine();
+ void testSimpleLine_data();
+
+ void testLineContinue();
+ void testLineContinue_data();
+ void testEditingLineContinue0();
+ void testEditingLineContinue1();
+ void testEditingLineContinue2();
+ void testEditingLineContinue3();
+ void testEditingLineContinue4();
+ void testEditingLineContinue5();
+
+ void testPersistentStates();
+ void testPersistentStates_data();
+ void testEditingPersistentStates0();
+ void testEditingPersistentStates1();
+ void testEditingPersistentStates2();
+
+ void testDynamicContexts();
+ void testDynamicContexts_data();
+
+private:
+ void createKeywords();
+ void createContexts();
+ void createItemDatas();
+
+ void setExpectedData(int state, const HighlightSequence &seq);
+ void setExpectedData(const QList<int> &states, const QList<HighlightSequence> &seqs);
+ void createColumns();
+ void test();
+ void test(int state, const HighlightSequence &seq, const QString &line);
+ void test(const QList<int> &states, const QList<HighlightSequence> &seqs, const QString &lines);
+
+ void clear(QList<int> *states, QList<HighlightSequence> *sequences) const;
+
+ QList<int> createlDefaultStatesList(int size) const;
+
+ void addCharactersToBegin(QTextBlock block, const QString &s);
+ void addCharactersToEnd(QTextBlock block, const QString &s);
+ void removeFirstCharacters(const QTextBlock &block, int n);
+ void removeLastCharacters(const QTextBlock &block, int n);
+
+ void setupForEditingLineContinue();
+
+ QSharedPointer<HighlightDefinition> m_definition;
+ QScopedPointer<HighlighterMock> m_highlighterMock;
+ QPlainTextEdit m_text;
+};
+
+tst_HighlighterEngine::tst_HighlighterEngine() :
+ m_definition(new HighlightDefinition)
+{}
+
+void tst_HighlighterEngine::initTestCase()
+{
+ QWARN("\n***********************************************************\
+ \n*** Spaces are ignored when comparing text char formats ***\
+ \n***********************************************************");
+
+ createKeywords();
+ createContexts();
+ createItemDatas();
+
+ m_highlighterMock.reset(new HighlighterMock(m_definition->initialContext()));
+ m_highlighterMock->setDocument(m_text.document());
+ m_highlighterMock->configureFormat(Highlighter::Keyword, Formats::instance().keywordFormat());
+ m_highlighterMock->configureFormat(Highlighter::DataType, Formats::instance().dataTypeFormat());
+ m_highlighterMock->configureFormat(Highlighter::Decimal, Formats::instance().decimalFormat());
+ m_highlighterMock->configureFormat(Highlighter::BaseN, Formats::instance().baseNFormat());
+ m_highlighterMock->configureFormat(Highlighter::Float, Formats::instance().floatFormat());
+ m_highlighterMock->configureFormat(Highlighter::Char, Formats::instance().charFormat());
+ m_highlighterMock->configureFormat(Highlighter::String, Formats::instance().stringFormat());
+ m_highlighterMock->configureFormat(Highlighter::Comment, Formats::instance().commentFormat());
+ m_highlighterMock->configureFormat(Highlighter::Alert, Formats::instance().alertFormat());
+ m_highlighterMock->configureFormat(Highlighter::Error, Formats::instance().errorFormat());
+ m_highlighterMock->configureFormat(Highlighter::Function, Formats::instance().functionFormat());
+ m_highlighterMock->configureFormat(Highlighter::RegionMarker,
+ Formats::instance().regionMarketFormat());
+ m_highlighterMock->configureFormat(Highlighter::Others, Formats::instance().othersFormat());
+}
+
+void tst_HighlighterEngine::init()
+{
+ m_highlighterMock->reset();
+}
+
+void tst_HighlighterEngine::createKeywords()
+{
+ QSharedPointer<KeywordList> keywords = m_definition->createKeywordList("keywords");
+ keywords->addKeyword("int");
+ keywords->addKeyword("long");
+}
+
+void tst_HighlighterEngine::createContexts()
+{
+ // Normal context
+ QSharedPointer<Context> normal = m_definition->createContext("Normal", true);
+ normal->setItemData("Normal Text");
+ normal->setLineEndContext("#stay");
+ normal->setDefinition(m_definition);
+
+ // AfterHash context
+ QSharedPointer<Context> afterHash = m_definition->createContext("AfterHash", false);
+ afterHash->setItemData("Error");
+ afterHash->setLineEndContext("#pop");
+ afterHash->setDefinition(m_definition);
+
+ // Define context
+ QSharedPointer<Context> define = m_definition->createContext("Define", false);
+ define->setItemData("Preprocessor");
+ define->setLineEndContext("#pop");
+ define->setDefinition(m_definition);
+
+ // Preprocessor context
+ QSharedPointer<Context> preprocessor = m_definition->createContext("Preprocessor", false);
+ preprocessor->setItemData("Preprocessor");
+ preprocessor->setLineEndContext("#pop");
+ preprocessor->setDefinition(m_definition);
+
+ // SimpleComment context
+ QSharedPointer<Context> simpleComment = m_definition->createContext("SimpleComment", false);
+ simpleComment->setItemData("Comment");
+ simpleComment->setLineEndContext("#pop");
+ simpleComment->setDefinition(m_definition);
+
+ // MultilineComment context
+ QSharedPointer<Context> multiComment = m_definition->createContext("MultilineComment", false);
+ multiComment->setItemData("Comment");
+ multiComment->setLineEndContext("#stay");
+ multiComment->setDefinition(m_definition);
+
+ // NestedComment context
+ QSharedPointer<Context> nestedComment = m_definition->createContext("NestedComment", false);
+ nestedComment->setItemData("Other Comment");
+ nestedComment->setLineEndContext("#stay");
+ nestedComment->setDefinition(m_definition);
+
+ // Dummy context
+ QSharedPointer<Context> dummy = m_definition->createContext("Dummy", false);
+ dummy->setItemData("Dummy");
+ dummy->setLineEndContext("#pop");
+ dummy->setDefinition(m_definition);
+
+ // AfterPlus context
+ QSharedPointer<Context> afterPlus = m_definition->createContext("AfterPlus", false);
+ afterPlus->setItemData("Char");
+ afterPlus->setLineEndContext("#pop");
+ afterPlus->setDefinition(m_definition);
+
+ // AfterMinus context
+ QSharedPointer<Context> afterMinus = m_definition->createContext("AfterMinus", false);
+ afterMinus->setItemData("String");
+ afterMinus->setLineEndContext("#pop#pop");
+ afterMinus->setDefinition(m_definition);
+
+ // AfterEqual context
+ QSharedPointer<Context> afterEqual = m_definition->createContext("AfterEqual", false);
+ afterEqual->setItemData("Float");
+ afterEqual->setLineEndContext("#pop#pop#pop");
+ afterEqual->setDefinition(m_definition);
+
+ // Dynamic context
+ QSharedPointer<Context> dynamic = m_definition->createContext("Dynamic", false);
+ dynamic->setItemData("Marker");
+ dynamic->setLineEndContext("#pop");
+ dynamic->setDynamic("true");
+ dynamic->setDefinition(m_definition);
+
+ // Rules
+ DetectCharRule *r = new DetectCharRule;
+ r->setChar("?");
+ r->setContext("#stay");
+ r->setItemData("Decimal");
+ r->setDefinition(m_definition);
+ normal->addRule(QSharedPointer<Rule>(r)); // Needs to be the first one added.
+
+ DetectCharRule *r0 = new DetectCharRule;
+ r0->setChar("#");
+ r0->setContext("AfterHash");
+ r0->setFirstNonSpace("true");
+ r0->setLookAhead("true");
+ r0->setDefinition(m_definition);
+ normal->addRule(QSharedPointer<Rule>(r0));
+
+ RegExprRule *r1 = new RegExprRule;
+ r1->setPattern("#\\s*define.*((?=\\\\))");
+ r1->setInsensitive("true");
+ r1->setContext("Define");
+ r1->setItemData("Preprocessor");
+ r1->setFirstNonSpace("true");
+ r1->setDefinition(m_definition);
+ afterHash->addRule(QSharedPointer<Rule>(r1));
+
+ RegExprRule *r2 = new RegExprRule;
+ r2->setPattern("#\\s*(?:define|undef)");
+ r2->setInsensitive("true");
+ r2->setContext("Preprocessor");
+ r2->setItemData("Preprocessor");
+ r2->setFirstNonSpace("true");
+ r2->setDefinition(m_definition);
+ afterHash->addRule(QSharedPointer<Rule>(r2));
+
+ LineContinueRule *r3 = new LineContinueRule;
+ r3->setItemData("Preprocessor");
+ r3->setContext("#stay");
+ r3->setDefinition(m_definition);
+ define->addRule(QSharedPointer<Rule>(r3));
+
+ LineContinueRule *r4 = new LineContinueRule;
+ r4->setItemData("Preprocessor");
+ r4->setContext("#stay");
+ r4->setDefinition(m_definition);
+ preprocessor->addRule(QSharedPointer<Rule>(r4));
+
+ KeywordRule *r5 = new KeywordRule(m_definition);
+ r5->setList("keywords");
+ r5->setItemData("Keyword");
+ r5->setContext("#stay");
+ r5->setDefinition(m_definition);
+ normal->addRule(QSharedPointer<Rule>(r5));
+
+ IntRule *r6 = new IntRule;
+ r6->setItemData("Decimal");
+ r6->setContext("#stay");
+ r6->setDefinition(m_definition);
+ normal->addRule(QSharedPointer<Rule>(r6));
+
+ StringDetectRule *r7 = new StringDetectRule;
+ r7->setItemData("Decimal");
+ r7->setContext("#stay");
+ r7->setString("LL");
+ r7->setInsensitive("true");
+ r7->setDefinition(m_definition);
+ r6->addChild(QSharedPointer<Rule>(r7));
+
+ StringDetectRule *r8 = new StringDetectRule;
+ r8->setItemData("Decimal");
+ r8->setContext("#stay");
+ r8->setString("UL");
+ r8->setInsensitive("true");
+ r8->setDefinition(m_definition);
+ r6->addChild(QSharedPointer<Rule>(r8));
+
+ HlCOctRule *r9 = new HlCOctRule;
+ r9->setItemData("Octal");
+ r9->setContext("#stay");
+ r9->setDefinition(m_definition);
+ normal->addRule(QSharedPointer<Rule>(r9));
+
+ Detect2CharsRule *r10 = new Detect2CharsRule;
+ r10->setChar("/");
+ r10->setChar1("/");
+ r10->setItemData("Comment");
+ r10->setContext("SimpleComment");
+ r10->setDefinition(m_definition);
+ normal->addRule(QSharedPointer<Rule>(r10));
+
+ DetectIdentifierRule *r11 = new DetectIdentifierRule;
+ r11->setDefinition(m_definition);
+ simpleComment->addRule(QSharedPointer<Rule>(r11));
+
+ Detect2CharsRule *r12 = new Detect2CharsRule;
+ r12->setChar("/");
+ r12->setChar1("*");
+ r12->setItemData("Comment");
+ r12->setContext("MultilineComment");
+ r12->setDefinition(m_definition);
+ normal->addRule(QSharedPointer<Rule>(r12));
+
+ Detect2CharsRule *r13 = new Detect2CharsRule;
+ r13->setChar("*");
+ r13->setChar1("/");
+ r13->setItemData("Comment");
+ r13->setContext("#pop");
+ r13->setDefinition(m_definition);
+ multiComment->addRule(QSharedPointer<Rule>(r13));
+
+ Detect2CharsRule *r14 = new Detect2CharsRule;
+ r14->setChar("/");
+ r14->setChar1("#");
+ r14->setItemData("Other Comment");
+ r14->setContext("NestedComment");
+ r14->setDefinition(m_definition);
+ QSharedPointer<Rule> sr14(r14);
+ multiComment->addRule(sr14);
+ dummy->addRule(sr14);
+ afterEqual->addRule(sr14);
+ afterMinus->addRule(sr14);
+ afterPlus->addRule(sr14);
+
+ Detect2CharsRule *r15 = new Detect2CharsRule;
+ r15->setChar("#");
+ r15->setChar1("/");
+ r15->setItemData("Other Comment");
+ r15->setContext("#pop");
+ r15->setDefinition(m_definition);
+ nestedComment->addRule(QSharedPointer<Rule>(r15));
+
+ DetectCharRule *r16 = new DetectCharRule;
+ r16->setChar("@");
+ r16->setItemData("Marker");
+ r16->setContext("Dummy");
+ r16->setDefinition(m_definition);
+ multiComment->addRule(QSharedPointer<Rule>(r16));
+
+ StringDetectRule *r17 = new StringDetectRule;
+ r17->setString("dummy");
+ r17->setItemData("Dummy");
+ r17->setContext("#stay");
+ r17->setDefinition(m_definition);
+ dummy->addRule(QSharedPointer<Rule>(r17));
+
+ DetectCharRule *r18 = new DetectCharRule;
+ r18->setChar("+");
+ r18->setContext("AfterPlus");
+ r18->setDefinition(m_definition);
+ QSharedPointer<Rule> sr18(r18);
+ multiComment->addRule(sr18);
+ nestedComment->addRule(sr18);
+ afterMinus->addRule(sr18);
+ afterEqual->addRule(sr18);
+
+ DetectCharRule *r19 = new DetectCharRule;
+ r19->setChar("-");
+ r19->setContext("AfterMinus");
+ r19->setDefinition(m_definition);
+ QSharedPointer<Rule> sr19(r19);
+ multiComment->addRule(sr19);
+ nestedComment->addRule(sr19);
+ afterPlus->addRule(sr19);
+ afterEqual->addRule(sr19);
+
+ DetectCharRule *r20 = new DetectCharRule;
+ r20->setChar("=");
+ r20->setContext("AfterEqual");
+ r20->setDefinition(m_definition);
+ QSharedPointer<Rule> sr20(r20);
+ multiComment->addRule(sr20);
+ nestedComment->addRule(sr20);
+ afterPlus->addRule(sr20);
+ afterMinus->addRule(sr20);
+
+ DetectCharRule *r22 = new DetectCharRule;
+ r22->setChar("$");
+ r22->setContext("#stay");
+ r22->setDefinition(m_definition);
+ normal->addRule(QSharedPointer<Rule>(r22));
+
+ DetectCharRule *r23 = new DetectCharRule;
+ r23->setChar("?");
+ r23->setContext("#stay");
+ r23->setItemData("Comment");
+ r23->setDefinition(m_definition);
+ normal->addRule(QSharedPointer<Rule>(r23));
+
+ RegExprRule *r24 = new RegExprRule;
+ r24->setInsensitive("true");
+ r24->setPattern("---([a-c]*)([d-f]*)");
+ r24->setDefinition(m_definition);
+ r24->setItemData("Dummy");
+ r24->setContext("Dynamic");
+ normal->addRule(QSharedPointer<Rule>(r24));
+
+ DetectCharRule *r25 = new DetectCharRule;
+ r25->setChar("1");
+ r25->setItemData("Preprocessor");
+ r25->setActive("true");
+ r25->setDefinition(m_definition);
+ dynamic->addRule(QSharedPointer<Rule>(r25));
+
+ StringDetectRule *r26 = new StringDetectRule;
+ r26->setString("begin%2end");
+ r26->setItemData("Error");
+ r26->setActive("true");
+ r26->setDefinition(m_definition);
+ dynamic->addRule(QSharedPointer<Rule>(r26));
+}
+
+void tst_HighlighterEngine::createItemDatas()
+{
+ QSharedPointer<ItemData> normalText = m_definition->createItemData("Normal Text");
+ normalText->setStyle("dsNormal");
+ QSharedPointer<ItemData> preprocessor = m_definition->createItemData("Preprocessor");
+ preprocessor->setStyle("dsOthers");
+ QSharedPointer<ItemData> error = m_definition->createItemData("Error");
+ error->setStyle("dsError");
+ QSharedPointer<ItemData> keyword = m_definition->createItemData("Keyword");
+ keyword->setStyle("dsKeyword");
+ QSharedPointer<ItemData> decimal = m_definition->createItemData("Decimal");
+ decimal->setStyle("dsDecVal");
+ QSharedPointer<ItemData> octal = m_definition->createItemData("Octal");
+ octal->setStyle("dsBaseN");
+ QSharedPointer<ItemData> comment = m_definition->createItemData("Comment");
+ comment->setStyle("dsComment");
+ QSharedPointer<ItemData> otherComment = m_definition->createItemData("Other Comment");
+ otherComment->setStyle("dsError");
+ QSharedPointer<ItemData> marker = m_definition->createItemData("Marker");
+ marker->setStyle("dsRegionMarker");
+ QSharedPointer<ItemData> dummy = m_definition->createItemData("Dummy");
+ dummy->setStyle("dsDataType");
+ QSharedPointer<ItemData> charStyle = m_definition->createItemData("Char");
+ charStyle->setStyle("dsChar");
+ QSharedPointer<ItemData> stringStyle = m_definition->createItemData("String");
+ stringStyle->setStyle("dsString");
+ QSharedPointer<ItemData> floatStyle = m_definition->createItemData("Float");
+ floatStyle->setStyle("dsFloat");
+}
+
+void tst_HighlighterEngine::setExpectedData(int state, const HighlightSequence &seq)
+{
+ m_highlighterMock->setExpectedBlockState(state);
+ m_highlighterMock->setExpectedHighlightSequence(seq);
+}
+
+void tst_HighlighterEngine::setExpectedData(const QList<int> &states,
+ const QList<HighlightSequence> &seqs)
+{
+ m_highlighterMock->setExpectedBlockStates(states);
+ m_highlighterMock->setExpectedHighlightSequences(seqs);
+}
+
+void tst_HighlighterEngine::createColumns()
+{
+ QTest::addColumn<QList<int> >("states");
+ QTest::addColumn<QList<HighlightSequence> >("sequences");
+ QTest::addColumn<QString>("lines");
+}
+
+void tst_HighlighterEngine::test()
+{
+ QFETCH(QList<int>, states);
+ QFETCH(QList<HighlightSequence>, sequences);
+ QFETCH(QString, lines);
+
+ test(states, sequences, lines);
+}
+
+void tst_HighlighterEngine::test(int state, const HighlightSequence &seq, const QString &line)
+{
+ setExpectedData(state, seq);
+ m_text.setPlainText(line);
+}
+
+void tst_HighlighterEngine::test(const QList<int> &states,
+ const QList<HighlightSequence> &seqs,
+ const QString &lines)
+{
+ setExpectedData(states, seqs);
+ m_text.setPlainText(lines);
+}
+
+void tst_HighlighterEngine::clear(QList<int> *states, QList<HighlightSequence> *sequences) const
+{
+ states->clear();
+ sequences->clear();
+}
+
+QList<int> tst_HighlighterEngine::createlDefaultStatesList(int size) const
+{
+ QList<int> states;
+ for (int i = 0; i < size; ++i)
+ states.append(0);
+ return states;
+}
+
+void tst_HighlighterEngine::addCharactersToBegin(QTextBlock block, const QString &s)
+{
+ QTextCursor cursor = m_text.textCursor();
+ cursor.beginEditBlock();
+ cursor.setPosition(block.position());
+ cursor.insertText(s);
+ cursor.endEditBlock();
+}
+
+void tst_HighlighterEngine::addCharactersToEnd(QTextBlock block, const QString &s)
+{
+ QTextCursor cursor = m_text.textCursor();
+ cursor.beginEditBlock();
+ cursor.setPosition(block.position() + block.length() - 1);
+ cursor.insertText(s);
+ cursor.endEditBlock();
+}
+
+void tst_HighlighterEngine::removeFirstCharacters(const QTextBlock &block, int n)
+{
+ QTextCursor cursor = m_text.textCursor();
+ cursor.beginEditBlock();
+ cursor.setPosition(block.position());
+ cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, n);
+ cursor.removeSelectedText();
+ cursor.endEditBlock();
+}
+
+void tst_HighlighterEngine::removeLastCharacters(const QTextBlock &block, int n)
+{
+ QTextCursor cursor = m_text.textCursor();
+ cursor.beginEditBlock();
+ cursor.setPosition(block.position() + block.length() - 1);
+ cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, n);
+ cursor.removeSelectedText();
+ cursor.endEditBlock();
+}
+
+void tst_HighlighterEngine::testSimpleLine()
+{
+ test();
+}
+
+void tst_HighlighterEngine::testSimpleLine_data()
+{
+ createColumns();
+
+ QList<int> states;
+ QList<HighlightSequence> sequences;
+ QString text;
+
+ HighlightSequence seqa(0, 3);
+ HighlightSequence seqb(0, 15, Formats::instance().othersFormat());
+ HighlightSequence seqc(0, 1, Formats::instance().errorFormat());
+ HighlightSequence seqd(0, 3, Formats::instance().keywordFormat());
+ seqd.add(3, 8);
+ seqd.add(8, 9, Formats::instance().baseNFormat());
+ HighlightSequence seqe(0, 4, Formats::instance().keywordFormat());
+ seqe.add(4, 9);
+ seqe.add(9, 12, Formats::instance().decimalFormat());
+ HighlightSequence seqf(seqe);
+ seqf.add(12, 13);
+ HighlightSequence seqg(seqf);
+ seqg.add(13, 14);
+ HighlightSequence seqh(0, 8, Formats::instance().commentFormat());
+ HighlightSequence seqi(seqd);
+ seqi.add(9, 17, Formats::instance().commentFormat());
+ HighlightSequence seqj(seqd);
+ seqj.add(9, 11, Formats::instance().commentFormat());
+ HighlightSequence seqk(0, 3);
+ HighlightSequence seql(0, 3, Formats::instance().keywordFormat());
+ HighlightSequence seqm(0, 2);
+ HighlightSequence seqn(0, 8, Formats::instance().commentFormat());
+ HighlightSequence seqo(0, 1);
+ seqo.add(1, 2, Formats::instance().decimalFormat());
+
+ states << 0;
+ sequences << seqa;
+ text = "abc";
+ QTest::newRow("case 0") << states << sequences << text;
+
+ sequences.clear();
+ sequences << seqb;
+ text = "#define max 100";
+ QTest::newRow("case 1") << states << sequences << text;
+
+ sequences.clear();
+ sequences << seqc;
+ text = "#";
+ QTest::newRow("case 2") << states << sequences << text;
+
+ sequences.clear();
+ sequences << seqd;
+ text = "int i = 0";
+ QTest::newRow("case 3") << states << sequences << text;
+
+ sequences.clear();
+ sequences << seqe;
+ text = "long i = 1LL";
+ QTest::newRow("case 4") << states << sequences << text;
+
+ text = "long i = 1ul";
+ QTest::newRow("case 5") << states << sequences << text;
+
+ sequences.clear();
+ sequences << seqf;
+ text = "long i = 1ULL";
+ QTest::newRow("case 6") << states << sequences << text;
+
+ sequences.clear();
+ sequences << seqg;
+ text = "long i = 1LLUL";
+ QTest::newRow("case 7") << states << sequences << text;
+
+ text = "long i = 1ULLL";
+ QTest::newRow("case 8") << states << sequences << text;
+
+ sequences.clear();
+ sequences << seqh;
+ text = "//int i;";
+ QTest::newRow("case 9") << states << sequences << text;
+
+ sequences.clear();
+ sequences << seqi;
+ text = "int i = 0//int i;";
+ QTest::newRow("case 10") << states << sequences << text;
+
+ sequences.clear();
+ sequences << seqj;
+ text = "int i = 0//";
+ QTest::newRow("case 11") << states << sequences << text;
+
+ sequences.clear();
+ sequences << seqk << seqk;
+ text = "bla\nbla";
+ QTest::newRow("case 12") << createlDefaultStatesList(2) << sequences << text;
+
+ sequences.clear();
+ sequences << seql << seqm;
+ text = "int\ni;";
+ QTest::newRow("case 13") << createlDefaultStatesList(2) << sequences << text;
+
+ sequences.clear();
+ sequences << seqn << seqm;
+ text = "//int i;\ni;";
+ QTest::newRow("case 14") << createlDefaultStatesList(2) << sequences << text;
+
+ // Even when a matching rule does not take to another context, iteration over the rules
+ // should start over from the first rule in the current context.
+ sequences.clear();
+ sequences << seqo;
+ text = "$?";
+ QTest::newRow("case 15") << createlDefaultStatesList(2) << sequences << text;
+}
+
+void tst_HighlighterEngine::testLineContinue()
+{
+ test();
+}
+
+void tst_HighlighterEngine::testLineContinue_data()
+{
+ createColumns();
+
+ QList<int> states;
+ QList<HighlightSequence> sequences;
+ QString lines;
+
+ HighlightSequence seqa(0, 12, Formats::instance().othersFormat());
+ HighlightSequence seqb(0, 7, Formats::instance().othersFormat());
+ HighlightSequence seqc(0, 8, Formats::instance().othersFormat());
+ HighlightSequence seqd(0, 3, Formats::instance().othersFormat());
+ HighlightSequence seqe(0, 3, Formats::instance().keywordFormat());
+ seqe.add(3, 8);
+ seqe.add(8, 9, Formats::instance().baseNFormat());
+ seqe.add(9, 10);
+
+ states << 1 << 2;
+ sequences << seqa << seqb;
+ lines = "#define max\\\n 100";
+ QTest::newRow("case 0") << states << sequences << lines;
+
+ clear(&states, &sequences);
+ states << 1 << 1;
+ sequences << seqa << seqc;
+ lines = "#define max\\\n 100\\";
+ QTest::newRow("case 1") << states << sequences << lines;
+
+ clear(&states, &sequences);
+ states << 1 << 1 << 2;
+ sequences << seqa << seqc << seqd;
+ lines = "#define max\\\n 100\\\n000";
+ QTest::newRow("case 2") << states << sequences << lines;
+
+ clear(&states, &sequences);
+ states << 1 << 1 << 2 << 0;
+ sequences << seqa << seqc << seqd << seqe;
+ lines = "#define max\\\n 100\\\n000\nint i = 0;";
+ QTest::newRow("case 3") << states << sequences << lines;
+}
+
+void tst_HighlighterEngine::setupForEditingLineContinue()
+{
+ m_highlighterMock->startNoTestCalls();
+ m_text.setPlainText("#define max\\\n xxx\\\nzzz");
+ m_highlighterMock->endNoTestCalls();
+}
+
+void tst_HighlighterEngine::testEditingLineContinue0()
+{
+ setupForEditingLineContinue();
+
+ QList<HighlightSequence> sequences;
+ HighlightSequence seqa(0, 11, Formats::instance().othersFormat());
+ HighlightSequence seqb(0, 8);
+ HighlightSequence seqc(0, 3);
+ sequences << seqa << seqb << seqc;
+ setExpectedData(createlDefaultStatesList(3), sequences);
+
+ removeLastCharacters(m_text.document()->firstBlock(), 1);
+}
+
+void tst_HighlighterEngine::testEditingLineContinue1()
+{
+ setupForEditingLineContinue();
+
+ setExpectedData(1, HighlightSequence(0, 6, Formats::instance().othersFormat()));
+
+ // In this case highlighting should be triggered only for the modified line.
+ removeFirstCharacters(m_text.document()->firstBlock().next(), 2);
+}
+
+void tst_HighlighterEngine::testEditingLineContinue2()
+{
+ setupForEditingLineContinue();
+
+ QList<HighlightSequence> sequences;
+ HighlightSequence seqa(0, 17, Formats::instance().othersFormat());
+ HighlightSequence seqb(0, 8);
+ HighlightSequence seqc(0, 3);
+ sequences << seqa << seqb << seqc;
+ setExpectedData(createlDefaultStatesList(3), sequences);
+
+ addCharactersToEnd(m_text.document()->firstBlock(), "ixum");
+}
+
+void tst_HighlighterEngine::testEditingLineContinue3()
+{
+ setupForEditingLineContinue();
+
+ setExpectedData(1, HighlightSequence(0, 12, Formats::instance().othersFormat()));
+
+ // In this case highlighting should be triggered only for the modified line.
+ addCharactersToBegin(m_text.document()->firstBlock().next(), "ixum");
+}
+
+void tst_HighlighterEngine::testEditingLineContinue4()
+{
+ setupForEditingLineContinue();
+
+ QList<int> states;
+ states << 2 << 0 << 0;
+ QList<HighlightSequence> sequences;
+ HighlightSequence seqa(0, 0);
+ HighlightSequence seqb(0, 8);
+ HighlightSequence seqc(0, 3);
+ sequences << seqa << seqb << seqc;
+ setExpectedData(states, sequences);
+
+ m_highlighterMock->considerEmptyLines();
+ addCharactersToBegin(m_text.document()->firstBlock().next(), "\n");
+}
+
+void tst_HighlighterEngine::testEditingLineContinue5()
+{
+ setupForEditingLineContinue();
+
+ QList<int> states;
+ states << 2 << 0;
+ QList<HighlightSequence> sequences;
+ HighlightSequence seqa(0, 9, Formats::instance().othersFormat());
+ HighlightSequence seqb(0, 3);
+ sequences << seqa << seqb;
+ setExpectedData(states, sequences);
+
+ addCharactersToEnd(m_text.document()->firstBlock().next(), "x");
+}
+
+void tst_HighlighterEngine::testPersistentStates()
+{
+ test();
+}
+
+void tst_HighlighterEngine::testPersistentStates_data()
+{
+ createColumns();
+
+ QList<int> states;
+ QList<HighlightSequence> sequences;
+ QString text;
+
+ HighlightSequence seqa(0, 3, Formats::instance().keywordFormat());
+ seqa.add(3, 6);
+ seqa.add(6, 15, Formats::instance().commentFormat());
+ seqa.add(15, 16);
+ HighlightSequence seqb(0, 8, Formats::instance().commentFormat());
+ HighlightSequence seqc(0, 2, Formats::instance().commentFormat());
+ HighlightSequence seqd(0, 9, Formats::instance().commentFormat());
+ seqd.add(9, 18, Formats::instance().errorFormat());
+ HighlightSequence seqe(0, 5, Formats::instance().errorFormat());
+ seqe.add(5, 8, Formats::instance().commentFormat());
+ HighlightSequence seqf(0, 2, Formats::instance().commentFormat());
+ seqf.add(2, 6);
+ HighlightSequence seqg(0, 1);
+ seqg.add(1, 7, Formats::instance().commentFormat());
+ seqg.add(7, 8, Formats::instance().regionMarketFormat());
+ seqg.add(8, 15, Formats::instance().errorFormat());
+ seqg.add(15, 16, Formats::instance().regionMarketFormat());
+ seqg.add(16, 21, Formats::instance().dataTypeFormat());
+ seqg.add(21, 22, Formats::instance().regionMarketFormat());
+ HighlightSequence seqh(seqc);
+ seqh.add(2, 3);
+ HighlightSequence seqi(seqc);
+ seqi.add(2, 3, Formats::instance().charFormat());
+ seqi.add(3, 4, Formats::instance().stringFormat());
+ HighlightSequence seqj(seqc);
+ seqj.add(2, 3, Formats::instance().charFormat());
+ seqj.add(3, 4, Formats::instance().floatFormat());
+ HighlightSequence seqk(seqc);
+ seqk.add(2, 3, Formats::instance().charFormat());
+ seqk.add(3, 5, Formats::instance().errorFormat());
+ seqk.add(5, 6, Formats::instance().floatFormat());
+ HighlightSequence seql(seqk);
+ seql.add(6, 7, Formats::instance().stringFormat());
+
+ states << 0;
+ sequences << seqa;
+ text = "int i /* 000 */;";
+ QTest::newRow("case 0") << states << sequences << text;
+
+ clear(&states, &sequences);
+ states << 3 << 3;
+ sequences << seqb << seqc;
+ text = "/*int i;\ni;";
+ QTest::newRow("case 1") << states << sequences << text;
+
+ clear(&states, &sequences);
+ states << 3 << 3 << 3;
+ sequences << seqb << seqc << seqb;
+ text = "/*int i;\ni;\nint abc;";
+ QTest::newRow("case 2") << states << sequences << text;
+
+ clear(&states, &sequences);
+ states << 3 << 3 << 0;
+ sequences << seqb << seqc << seqc;
+ text = "/*int i;\ni;\n*/";
+ QTest::newRow("case 3") << states << sequences << text;
+
+ clear(&states, &sequences);
+ states << 4 << 3 << 0;
+ sequences << seqd << seqe << seqf;
+ text = "/*int i; /# int j;\nfoo#/bar\n*/f();";
+ QTest::newRow("case 4") << states << sequences << text;
+
+ clear(&states, &sequences);
+ states << 3;
+ sequences << seqg;
+ text = "i/*bla @/#foo#/ dummy ";
+ QTest::newRow("case 5") << states << sequences << text;
+
+ clear(&states, &sequences);
+ states << 3 << 3;
+ sequences << seqg << seqc;
+ text = "i/*bla @/#foo#/ dummy \ni;";
+ QTest::newRow("case 6") << states << sequences << text;
+
+ clear(&states, &sequences);
+ states << 3 << 3 << 0;
+ sequences << seqg << seqc << seqc;
+ text = "i/*bla @/#foo#/ dummy \ni;\n*/";
+ QTest::newRow("case 7") << states << sequences << text;
+
+ clear(&states, &sequences);
+ states << 3 << 3 << 0;
+ sequences << seqg << seqc << seqh;
+ text = "i/*bla @/#foo#/ dummy \ni;\n*/a";
+ QTest::newRow("case 8") << states << sequences << text;
+
+ clear(&states, &sequences);
+ states << 3;
+ sequences << seqi;
+ text = "/*+-";
+ QTest::newRow("case 9") << states << sequences << text;
+
+ clear(&states, &sequences);
+ states << 0;
+ sequences << seqj;
+ text = "/*+=";
+ QTest::newRow("case 10") << states << sequences << text;
+
+ clear(&states, &sequences);
+ states << 3;
+ sequences << seqk;
+ text = "/*+/#=";
+ QTest::newRow("case 11") << states << sequences << text;
+
+ clear(&states, &sequences);
+ states << 6;
+ sequences << seql;
+ text = "/*+/#=-";
+ QTest::newRow("case 12") << states << sequences << text;
+}
+
+void tst_HighlighterEngine::testEditingPersistentStates0()
+{
+ m_highlighterMock->startNoTestCalls();
+ m_text.setPlainText("a b c /\ninside\n*/\na b c");
+ m_highlighterMock->endNoTestCalls();
+
+ QList<int> states;
+ states << 3 << 3 << 0 << 0;
+ QList<HighlightSequence> sequences;
+ HighlightSequence seqa(0, 6);
+ seqa.add(6, 8, Formats::instance().commentFormat());
+ HighlightSequence seqb(0, 6, Formats::instance().commentFormat());
+ HighlightSequence seqc(0, 2, Formats::instance().commentFormat());
+ HighlightSequence seqd(0, 5);
+ sequences << seqa << seqb << seqc << seqd;
+ setExpectedData(states, sequences);
+
+ addCharactersToEnd(m_text.document()->firstBlock(), "*");
+}
+
+void tst_HighlighterEngine::testEditingPersistentStates1()
+{
+ m_highlighterMock->startNoTestCalls();
+ m_text.setPlainText("/*abc\n/\nnesting\nnesting\n#/\n*/xyz");
+ m_highlighterMock->endNoTestCalls();
+
+ QList<int> states;
+ states << 4 << 4 << 4 << 3 << 0;
+ QList<HighlightSequence> sequences;
+ HighlightSequence seqa(0, 2, Formats::instance().errorFormat());
+ HighlightSequence seqb(0, 7, Formats::instance().errorFormat());
+ HighlightSequence seqc(seqb);
+ HighlightSequence seqd(0, 2, Formats::instance().errorFormat());
+ HighlightSequence seqe(0, 2, Formats::instance().commentFormat());
+ seqe.add(2, 5);
+ sequences << seqa << seqb << seqc << seqd << seqe;
+ setExpectedData(states, sequences);
+
+ addCharactersToEnd(m_text.document()->firstBlock().next(), "#");
+}
+
+void tst_HighlighterEngine::testEditingPersistentStates2()
+{
+ m_highlighterMock->startNoTestCalls();
+ m_text.setPlainText("/*abc\n/\nnesting\nnesting\n*/\n#/xyz");
+ m_highlighterMock->endNoTestCalls();
+
+ QList<int> states;
+ states << 4 << 4 << 4 << 4 << 3;
+ QList<HighlightSequence> sequences;
+ HighlightSequence seqa(0, 2, Formats::instance().errorFormat());
+ HighlightSequence seqb(0, 7, Formats::instance().errorFormat());
+ HighlightSequence seqc(seqb);
+ HighlightSequence seqd(0, 2, Formats::instance().errorFormat());
+ HighlightSequence seqe(seqd);
+ seqe.add(2, 5, Formats::instance().commentFormat());
+ sequences << seqa << seqb << seqc << seqd << seqe;
+ setExpectedData(states, sequences);
+
+ addCharactersToEnd(m_text.document()->firstBlock().next(), "#");
+}
+
+void tst_HighlighterEngine::testDynamicContexts()
+{
+ test();
+}
+
+void tst_HighlighterEngine::testDynamicContexts_data()
+{
+ createColumns();
+
+ QList<int> states;
+ QList<HighlightSequence> sequences;
+ QString text;
+
+ HighlightSequence seqa(0, 2);
+ seqa.add(2, 15, Formats::instance().dataTypeFormat());
+ seqa.add(15, 16, Formats::instance().othersFormat());
+ seqa.add(16, 17, Formats::instance().regionMarketFormat());
+ HighlightSequence seqb(seqa);
+ seqb.add(17, 31, Formats::instance().errorFormat());
+
+ states << 0;
+ sequences << seqa;
+ text = "a ---abcddeeff a ";
+ QTest::newRow("case 0") << states << sequences << text;
+
+ sequences.clear();
+ sequences << seqb;
+ text = "a ---abcddeeff a beginddeeffend";
+ QTest::newRow("case 1") << states << sequences << text;
+}
+
+QTEST_MAIN(tst_HighlighterEngine)
+#include "tst_highlighterengine.moc"
+
--- /dev/null
+QT += testlib
+
+PLUGINSDIR = ../../../../src/plugins
+
+SOURCES += tst_specificrules.cpp \
+ $$PLUGINSDIR/texteditor/generichighlighter/context.cpp \
+ $$PLUGINSDIR/texteditor/generichighlighter/dynamicrule.cpp \
+ $$PLUGINSDIR/texteditor/generichighlighter/rule.cpp \
+ $$PLUGINSDIR/texteditor/generichighlighter/specificrules.cpp \
+ $$PLUGINSDIR/texteditor/generichighlighter/progressdata.cpp \
+ $$PLUGINSDIR/texteditor/generichighlighter/highlightdefinition.cpp \
+ $$PLUGINSDIR/texteditor/generichighlighter/keywordlist.cpp \
+ $$PLUGINSDIR/texteditor/generichighlighter/itemdata.cpp
+
+INCLUDEPATH += $$PLUGINSDIR
+
+TARGET=tst_$$TARGET
--- /dev/null
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include <texteditor/generichighlighter/highlightdefinition.h>
+#include <texteditor/generichighlighter/keywordlist.h>
+#include <texteditor/generichighlighter/specificrules.h>
+#include <texteditor/generichighlighter/progressdata.h>
+
+#include <QtTest/QtTest>
+
+using namespace TextEditor;
+using namespace Internal;
+
+class tst_SpecificRules : public QObject
+{
+ Q_OBJECT
+public:
+ tst_SpecificRules() : m_definition(new HighlightDefinition) {}
+
+private slots:
+ void initTestCase();
+
+ void testDetectChar();
+ void testDetectChar_data();
+
+ void testDetect2Char();
+ void testDetect2Char_data();
+
+ void testAnyChar();
+ void testAnyChar_data();
+
+ void testStringDetect();
+ void testStringDetect_data();
+
+ void testRegExpr();
+ void testRegExpr_data();
+ void testRegExprOffsetIncremented();
+ void testRegExprOffsetIncremented_data();
+
+ void testKeywordGlobalSensitiveLocalSensitive();
+ void testKeywordGlobalSensitiveLocalSensitive_data();
+ void testKeywordGlobalSensitiveLocalInsensitive();
+ void testKeywordGlobalSensitiveLocalInsensitive_data();
+ void testKeywordGlobalInsensitiveLocalInsensitive();
+ void testKeywordGlobalInsensitiveLocalInsensitive_data();
+ void testKeywordGlobalInsensitiveLocalSensitive();
+ void testKeywordGlobalInsensitiveLocalSensitive_data();
+
+ void testInt();
+ void testInt_data();
+
+ void testFloat();
+ void testFloat_data();
+
+ void testCOctal();
+ void testCOctal_data();
+
+ void testCHex();
+ void testCHex_data();
+
+ void testCString();
+ void testCString_data();
+
+ void testCChar();
+ void testCChar_data();
+
+ void testRangeDetect();
+ void testRangeDetect_data();
+
+ void testLineContinue();
+ void testLineContinue_data();
+
+ void testDetectSpaces();
+ void testDetectSpaces_data();
+
+ void testDetectIdentifier();
+ void testDetectIdentifier_data();
+
+private:
+ void addCommonColumns() const;
+ void testMatch(const Rule &rule) const;
+ void testMatch(const Rule &rule, ProgressData *progress) const;
+
+ void noMatchForInt() const;
+ void noMatchForFloat() const;
+ void noMatchForCOctal() const;
+ void noMatchForCHex() const;
+ void noMatchForNumber() const;
+
+ void commonCasesForKeywords() const;
+
+ QSharedPointer<HighlightDefinition> m_definition;
+};
+
+void tst_SpecificRules::initTestCase()
+{
+ QSharedPointer<KeywordList> list = m_definition->createKeywordList("keywords");
+ list->addKeyword("for");
+ list->addKeyword("while");
+ list->addKeyword("BEGIN");
+ list->addKeyword("END");
+ list->addKeyword("WeIrD");
+}
+
+void tst_SpecificRules::addCommonColumns() const
+{
+ QTest::addColumn<QString>("s");
+ QTest::addColumn<bool>("match");
+ QTest::addColumn<int>("offset");
+ QTest::addColumn<bool>("only spaces");
+ QTest::addColumn<bool>("will continue");
+}
+
+void tst_SpecificRules::testMatch(const Rule &rule) const
+{
+ ProgressData progress;
+ testMatch(rule, &progress);
+}
+
+void tst_SpecificRules::testMatch(const Rule &rule, ProgressData *progress) const
+{
+ QFETCH(QString, s);
+
+ QTEST(rule.matchSucceed(s, s.length(), progress), "match");
+ QTEST(progress->offset(), "offset");
+ QTEST(progress->onlySpacesSoFar(), "only spaces");
+ QTEST(progress->willContinueLine(), "will continue");
+}
+
+void tst_SpecificRules::testDetectChar()
+{
+ QFETCH(QString, c);
+ DetectCharRule rule;
+ rule.setChar(c);
+
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testDetectChar_data()
+{
+ QTest::addColumn<QString>("c");
+ addCommonColumns();
+
+ QTest::newRow("[#] against [#]") << "#" << "#" << true << 1 << false << false;
+ QTest::newRow("[#] against [##]") << "#" << "##" << true << 1 << false << false;
+ QTest::newRow("[#] against [ ]") << "#" << " " << false << 0 << true << false;
+ QTest::newRow("[#] against [a]") << "#" << "a" << false << 0 << true << false;
+ QTest::newRow("[#] against [abc]") << "#" << "abc" << false << 0 << true << false;
+ QTest::newRow("[#] against [x#]") << "#" << "x#" << false << 0 << true << false;
+ QTest::newRow("[ ] against [a]") << " " << "a" << false << 0 << true << false;
+ //QTest::newRow("[ ] against [ ]") << " " << " " << true << 1 << true << false;
+}
+
+void tst_SpecificRules::testDetect2Char()
+{
+ QFETCH(QString, c);
+ QFETCH(QString, c1);
+ Detect2CharsRule rule;
+ rule.setChar(c);
+ rule.setChar1(c1);
+
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testDetect2Char_data()
+{
+ QTest::addColumn<QString>("c");
+ QTest::addColumn<QString>("c1");
+ addCommonColumns();
+
+ QTest::newRow("[//] against [//]") << "/" << "/" << "//" << true << 2 << false << false;
+ QTest::newRow("[//] against [///]") << "/" << "/" << "///" << true << 2 << false << false;
+ QTest::newRow("[//] against [// ]") << "/" << "/" << "// " << true << 2 << false << false;
+ QTest::newRow("[//] against [ //]") << "/" << "/" << " //" << false << 0 << true << false;
+ QTest::newRow("[//] against [a]") << "/" << "/" << "a" << false << 0 << true << false;
+ QTest::newRow("[//] against [ a]") << "/" << "/" << " a" << false << 0 << true << false;
+ QTest::newRow("[//] against [abc]") << "/" << "/" << "abc" << false << 0 << true << false;
+ QTest::newRow("[//] against [/a]") << "/" << "/" << "/a" << false << 0 << true << false;
+ QTest::newRow("[//] against [a/]") << "/" << "/" << "a/" << false << 0 << true << false;
+ QTest::newRow("[ ] against [xx]") << " " << " " << "xx" << false << 0 << true << false;
+ //QTest::newRow("[ ] against [ ]") << " " << " " << " " << true << 3 << true << false;
+}
+
+void tst_SpecificRules::testAnyChar()
+{
+ QFETCH(QString, chars);
+ AnyCharRule rule;
+ rule.setCharacterSet(chars);
+
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testAnyChar_data()
+{
+ QTest::addColumn<QString>("chars");
+ addCommonColumns();
+
+ QTest::newRow("[:!<>?] against [:]") << ":!<>?" << ":" << true << 1 << false << false;
+ QTest::newRow("[:!<>?] against [!]") << ":!<>?" << "!" << true << 1 << false << false;
+ QTest::newRow("[:!<>?] against [<]") << ":!<>?" << "<" << true << 1 << false << false;
+ QTest::newRow("[:!<>?] against [>]") << ":!<>?" << ">" << true << 1 << false << false;
+ QTest::newRow("[:!<>?] against [?]") << ":!<>?" << "?" << true << 1 << false << false;
+ QTest::newRow("[:!<>?] against [:]") << ":!<>?" << ":" << true << 1 << false << false;
+ QTest::newRow("[:!<>?] against [ ]") << ":!<>?" << " " << false << 0 << true << false;
+ QTest::newRow("[:!<>?] against [#]") << ":!<>?" << "#" << false << 0 << true << false;
+ QTest::newRow("[:!<>?] against [!#]") << ":!<>?" << "!#" << true << 1 << false << false;
+ QTest::newRow("[:!<>?] against [#!]") << ":!<>?" << "#!" << false << 0 << true << false;
+ QTest::newRow("[:] against [:]") << ":" << ":" << true << 1 << false << false;
+ QTest::newRow("[:] against [#]") << ":" << "#" << false << 0 << true << false;
+ //QTest::newRow("[ ] against [ ]") << " " << " " << true << 1 << true << false;
+}
+
+void tst_SpecificRules::testStringDetect()
+{
+ QFETCH(QString, referenceString);
+ QFETCH(QString, insensitive);
+ StringDetectRule rule;
+ rule.setString(referenceString);
+ rule.setInsensitive(insensitive);
+
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testStringDetect_data()
+{
+ QTest::addColumn<QString>("referenceString");
+ QTest::addColumn<QString>("insensitive");
+ addCommonColumns();
+
+ QTest::newRow("[LL] against [LL]") << "LL" << "0" << "LL" << true << 2 << false << false;
+ QTest::newRow("[LL] against [ll]") << "LL" << "0" << "ll" << false << 0 << true << false;
+ QTest::newRow("[LL] against [ll] i") << "LL" << "1" << "ll" << true << 2 << false << false;
+ QTest::newRow("[ll] against [ll] i") << "LL" << "1" << "LL" << true << 2 << false << false;
+ QTest::newRow("[LL] against [5LL]") << "LL" << "0" << "5LL" << false << 0 << true << false;
+ QTest::newRow("[LL] against [L]") << "LL" << "0" << "L" << false << 0 << true << false;
+ QTest::newRow("[LL] against [LLL]") << "LL" << "0" << "LLL" << true << 2 << false << false;
+ QTest::newRow("[LL] against [ ]") << "LL" << "0" << " " << false << 0 << true << false;
+ QTest::newRow("[LL] against [xLLx]") << "LL" << "0" << "xLLx" << false << 0 << true << false;
+ QTest::newRow("[\"\"\"] against [\"\"\"]") << "\"\"\"" << "0" << "\"\"\"" << true << 3
+ << false << false;
+}
+
+void tst_SpecificRules::testRegExpr()
+{
+ QFETCH(QString, pattern);
+ QFETCH(QString, insensitive);
+ QFETCH(QString, minimal);
+ RegExprRule rule;
+ rule.setPattern(pattern);
+ rule.setInsensitive(insensitive);
+ rule.setMinimal(minimal);
+
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testRegExpr_data()
+{
+ QTest::addColumn<QString>("pattern");
+ QTest::addColumn<QString>("insensitive");
+ QTest::addColumn<QString>("minimal");
+ addCommonColumns();
+
+ QTest::newRow("[#[a-z]+\\s+\\d] against [#as 9]") << "#[a-z]+\\s+\\d" << "0" << "0"
+ << "#as 9" << true << 5 << false << false;
+ QTest::newRow("[#[a-z]+\\s+\\d] against [#As 9]") << "#[a-z]+\\s+\\d" << "0" << "0"
+ << "#As 9" << false << 0 << true << false;
+ QTest::newRow("[#[a-z]+\\s+\\d] against [#As 9] i") << "#[a-z]+\\s+\\d" << "1" << "0"
+ << "#As 9" << true << 5 << false << false;
+ QTest::newRow("[#[a-z]+\\s+\\d] against [as 9]") << "#[a-z]+\\s+\\d" << "0" << "0"
+ << "as 9" << false << 0 << true << false;
+ QTest::newRow("[#[a-z]+\\s+\\d] against [w#as 9]") << "#[a-z]+\\s+\\d" << "0" << "0"
+ << "w#as 9" << false << 0 << true << false;
+ QTest::newRow("[^\\s+[a-z]] against [x]") << "^\\s+[a-z]" << "0" << "0"
+ << "x" << false << 0 << true << false;
+ QTest::newRow("[^\\s+[a-z]] against [ x]") << "^\\s+[a-z]" << "0" << "0"
+ << " x" << true << 3 << false << false;
+ QTest::newRow("[0+] against [1001]") << "0+" << "0" << "0"
+ << "1001" << false << 0 << true << false;
+ QTest::newRow("[0+] against [001]") << "0+" << "0" << "0"
+ << "001" << true << 2 << false << false;
+ QTest::newRow("[0+] against [001]") << "0+" << "0" << "1"
+ << "001" << true << 1 << false << false;
+ QTest::newRow("[\\s*] against []") << "\\s*" << "0" << "0"
+ << "" << false << 0 << true << false;
+ //QTest::newRow("[\\s*] against []") << "\\s*" << "0" << "0"
+ // << " " << true << 1 << true << false;
+}
+
+void tst_SpecificRules::testRegExprOffsetIncremented()
+{
+ QFETCH(QString, pattern);
+ RegExprRule rule;
+ rule.setPattern(pattern);
+
+ ProgressData progress;
+ progress.setOffset(1);
+
+ testMatch(rule, &progress);
+}
+
+void tst_SpecificRules::testRegExprOffsetIncremented_data()
+{
+ QTest::addColumn<QString>("pattern");
+ addCommonColumns();
+
+ // To make sure that QRegExp::CaretAtZero is set.
+ QTest::newRow("[^\\s+[a-z]] against [ x]") << "^\\s+[a-z]" << " x" << false << 1
+ << true << false;
+}
+
+void tst_SpecificRules::commonCasesForKeywords() const
+{
+ QTest::newRow("[for]") << "for" << true << 3 << false << false;
+ QTest::newRow("[while]") << "while" << true << 5 << false << false;
+ QTest::newRow("[BEGIN]") << "BEGIN" << true << 5 << false << false;
+ QTest::newRow("[END]") << "END" << true << 3 << false << false;
+ QTest::newRow("[WeIrD]") << "WeIrD" << true << 5 << false << false;
+ QTest::newRow("[forr]") << "forr" << false << 0 << true << false;
+ QTest::newRow("[for#]") << "for#" << false << 0 << true << false;
+ QTest::newRow("[abc]") << "abc" << false << 0 << true << false;
+ QTest::newRow("[ ]") << " " << false << 0 << true << false;
+ QTest::newRow("[foe]") << "foe" << false << 0 << true << false;
+ QTest::newRow("[sor]") << "sor" << false << 0 << true << false;
+ QTest::newRow("[ffor]") << "ffor" << false << 0 << true << false;
+
+ // Valid default delimiters.
+ QTest::newRow("[for ]") << "for " << true << 3 << false << false;
+ QTest::newRow("[for.for]") << "for.for" << true << 3 << false << false;
+ QTest::newRow("[for(]") << "for(" << true << 3 << false << false;
+ QTest::newRow("[for)]") << "for)" << true << 3 << false << false;
+ QTest::newRow("[for:]") << "for:" << true << 3 << false << false;
+ QTest::newRow("[for!]") << "for!" << true << 3 << false << false;
+ QTest::newRow("[for+]") << "for+" << true << 3 << false << false;
+ QTest::newRow("[for,]") << "for," << true << 3 << false << false;
+ QTest::newRow("[for-]") << "for-" << true << 3 << false << false;
+ QTest::newRow("[for<]") << "for>" << true << 3 << false << false;
+ QTest::newRow("[for=]") << "for=" << true << 3 << false << false;
+ QTest::newRow("[for>]") << "for>" << true << 3 << false << false;
+ QTest::newRow("[for%]") << "for%" << true << 3 << false << false;
+ QTest::newRow("[for&]") << "for&" << true << 3 << false << false;
+ QTest::newRow("[for/]") << "for/" << true << 3 << false << false;
+ QTest::newRow("[for;]") << "for;" << true << 3 << false << false;
+ QTest::newRow("[for?]") << "for?" << true << 3 << false << false;
+ QTest::newRow("[for[]") << "for[" << true << 3 << false << false;
+ QTest::newRow("[for]]") << "for]" << true << 3 << false << false;
+ QTest::newRow("[for^]") << "for^" << true << 3 << false << false;
+ QTest::newRow("[for{]") << "for{" << true << 3 << false << false;
+ QTest::newRow("[for|]") << "for|" << true << 3 << false << false;
+ QTest::newRow("[for}]") << "for}" << true << 3 << false << false;
+ QTest::newRow("[for~]") << "for~" << true << 3 << false << false;
+ QTest::newRow("[for\\]") << "for\\" << true << 3 << false << false;
+ QTest::newRow("[for*]") << "for*" << true << 3 << false << false;
+ QTest::newRow("[for,for]") << "for,for" << true << 3 << false << false;
+ QTest::newRow("[for\t]") << "for\t" << true << 3 << false << false;
+}
+
+void tst_SpecificRules::testKeywordGlobalSensitiveLocalSensitive()
+{
+ m_definition->setKeywordsSensitive("true");
+ KeywordRule rule(m_definition);
+ rule.setInsensitive("false");
+ rule.setList("keywords");
+
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testKeywordGlobalSensitiveLocalSensitive_data()
+{
+ addCommonColumns();
+
+ commonCasesForKeywords();
+ QTest::newRow("[fOr]") << "fOr" << false << 0 << true << false;
+ QTest::newRow("[whilE") << "whilE" << false << 0 << true << false;
+ QTest::newRow("[bEGIN]") << "bEGIN" << false << 0 << true << false;
+ QTest::newRow("[end]") << "end" << false << 0 << true << false;
+ QTest::newRow("[weird]") << "weird" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::testKeywordGlobalSensitiveLocalInsensitive()
+{
+ m_definition->setKeywordsSensitive("true");
+ KeywordRule rule(m_definition);
+ rule.setInsensitive("true");
+ rule.setList("keywords");
+
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testKeywordGlobalSensitiveLocalInsensitive_data()
+{
+ addCommonColumns();
+
+ commonCasesForKeywords();
+ QTest::newRow("[fOr]") << "fOr" << true << 3 << false << false;
+ QTest::newRow("[whilE") << "whilE" << true << 5 << false << false;
+ QTest::newRow("[bEGIN]") << "bEGIN" << true << 5 << false << false;
+ QTest::newRow("[end]") << "end" << true << 3 << false << false;
+ QTest::newRow("[weird]") << "weird" << true << 5 << false << false;
+}
+
+void tst_SpecificRules::testKeywordGlobalInsensitiveLocalInsensitive()
+{
+ m_definition->setKeywordsSensitive("false");
+ KeywordRule rule(m_definition);
+ rule.setInsensitive("true");
+ rule.setList("keywords");
+
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testKeywordGlobalInsensitiveLocalInsensitive_data()
+{
+ testKeywordGlobalSensitiveLocalInsensitive_data();
+}
+
+void tst_SpecificRules::testKeywordGlobalInsensitiveLocalSensitive()
+{
+ m_definition->setKeywordsSensitive("false");
+ KeywordRule rule(m_definition);
+ rule.setInsensitive("false");
+ rule.setList("keywords");
+
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testKeywordGlobalInsensitiveLocalSensitive_data()
+{
+ testKeywordGlobalSensitiveLocalSensitive_data();
+}
+
+void tst_SpecificRules::noMatchForInt() const
+{
+ QTest::newRow("[1]") << "1" << false << 0 << true << false;
+ QTest::newRow("[1299]") << "1299" << false << 0 << true << false;
+ QTest::newRow("[10]") << "10" << false << 0 << true << false;
+ QTest::newRow("[9]") << "9" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::noMatchForFloat() const
+{
+ QTest::newRow("[4e-11]") << "4e-11" << false << 0 << true << false;
+ QTest::newRow("[1e+5]") << "1e+5" << false << 0 << true << false;
+ QTest::newRow("[7.321E-3]") << "7.321E-3" << false << 0 << true << false;
+ QTest::newRow("[3.2E+4]") << "3.2E+4" << false << 0 << true << false;
+ QTest::newRow("[0.5e-6]") << "0.5e-6" << false << 0 << true << false;
+ QTest::newRow("[0.45]") << "0.45" << false << 0 << true << false;
+ QTest::newRow("[6.e10]") << "6.e10" << false << 0 << true << false;
+ QTest::newRow("[.2e23]") << ".2e23" << false << 0 << true << false;
+ QTest::newRow("[23.]") << "23." << false << 0 << true << false;
+ QTest::newRow("[2.e23]") << "2.e23" << false << 0 << true << false;
+ QTest::newRow("[23e2]") << "23e2" << false << 0 << true << false;
+ QTest::newRow("[4.3e]") << "4.3e" << false << 0 << true << false;
+ QTest::newRow("[4.3ef]") << "4.3ef" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::noMatchForCOctal() const
+{
+ QTest::newRow("[0]") << "0" << false << 0 << true << false;
+ QTest::newRow("[07]") << "07" << false << 0 << true << false;
+ QTest::newRow("[01234567]") << "01234567" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::noMatchForCHex() const
+{
+ QTest::newRow("[0X934AF]") << "0X934AF" << false << 0 << true << false;
+ QTest::newRow("[0x934af]") << "0x934af" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::noMatchForNumber() const
+{
+ QTest::newRow("[a]") << "a" << false << 0 << true << false;
+ QTest::newRow("[#]") << "#" << false << 0 << true << false;
+ QTest::newRow("[ ]") << " " << false << 0 << true << false;
+ QTest::newRow("[a1]") << "a1" << false << 0 << true << false;
+ QTest::newRow("[.e23]") << ".e23" << false << 0 << true << false;
+ QTest::newRow("[.e23]") << ".e23" << false << 0 << true << false;
+
+ // + and - are not directly matched by number rules.
+ QTest::newRow("[+1]") << "+1" << false << 0 << true << false;
+ QTest::newRow("[-1]") << "-1" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::testInt()
+{
+ IntRule rule;
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testInt_data()
+{
+ addCommonColumns();
+
+ noMatchForCOctal();
+ noMatchForCHex();
+ noMatchForNumber();
+
+ QTest::newRow("[1]") << "1" << true << 1 << false << false;
+ QTest::newRow("[1299]") << "1299" << true << 4 << false << false;
+ QTest::newRow("[10]") << "10" << true << 2 << false << false;
+ QTest::newRow("[9]") << "9" << true << 1 << false << false;
+
+ // LL, U, and others are matched through child rules.
+ QTest::newRow("[234U]") << "234U" << true << 3 << false << false;
+ QTest::newRow("[234LL]") << "234LL" << true << 3 << false << false;
+}
+
+void tst_SpecificRules::testFloat()
+{
+ FloatRule rule;
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testFloat_data()
+{
+ addCommonColumns();
+
+ noMatchForInt();
+ noMatchForCOctal();
+ noMatchForCHex();
+ noMatchForNumber();
+
+ QTest::newRow("[4e-11]") << "4e-11" << true << 5 << false << false;
+ QTest::newRow("[1e+5]") << "1e+5" << true << 4 << false << false;
+ QTest::newRow("[7.321E-3]") << "7.321E-3" << true << 8 << false << false;
+ QTest::newRow("[3.2E+4]") << "3.2E+4" << true << 6 << false << false;
+ QTest::newRow("[0.5e-6]") << "0.5e-6" << true << 6 << false << false;
+ QTest::newRow("[0.45]") << "0.45" << true << 4 << false << false;
+ QTest::newRow("[6.e10]") << "6.e10" << true << 5 << false << false;
+ QTest::newRow("[.2e23]") << ".2e23" << true << 5 << false << false;
+ QTest::newRow("[23.]") << "23." << true << 3 << false << false;
+ QTest::newRow("[2.e23]") << "2.e23" << true << 5 << false << false;
+ QTest::newRow("[23e2]") << "23e2" << true << 4 << false << false;
+
+ // F, L, and others are matched through child rules.
+ QTest::newRow("[6.e10f]") << "6.e10f" << true << 5 << false << false;
+ QTest::newRow("[0.5e-6F]") << "0.5e-6F" << true << 6 << false << false;
+ QTest::newRow("[23.f]") << "23.f" << true << 3 << false << false;
+ QTest::newRow("[.2L]") << ".2L" << true << 2 << false << false;
+}
+
+void tst_SpecificRules::testCOctal()
+{
+ HlCOctRule rule;
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testCOctal_data()
+{
+ addCommonColumns();
+
+ noMatchForInt();
+ noMatchForCHex();
+ noMatchForNumber();
+
+ QTest::newRow("[0]") << "0" << true << 1 << false << false;
+ QTest::newRow("[07]") << "07" << true << 2 << false << false;
+ QTest::newRow("[01234567]") << "01234567" << true << 8 << false << false;
+ QTest::newRow("[012345678]") << "012345678" << true << 8 << false << false;
+ QTest::newRow("[0888]") << "0888" << true << 1 << false << false;
+}
+
+void tst_SpecificRules::testCHex()
+{
+ HlCHexRule rule;
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testCHex_data()
+{
+ addCommonColumns();
+
+ noMatchForInt();
+ noMatchForFloat();
+ noMatchForCOctal();
+ noMatchForNumber();
+
+ QTest::newRow("[0X934AF]") << "0X934AF" << true << 7 << false << false;
+ QTest::newRow("[0x934af]") << "0x934af" << true << 7 << false << false;
+ QTest::newRow("[0x2ik]") << "0x2ik" << true << 3 << false << false;
+}
+
+void tst_SpecificRules::testCString()
+{
+ HlCStringCharRule rule;
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testCString_data()
+{
+ addCommonColumns();
+
+ // Escape sequences
+ QTest::newRow("[\\a]") << "\\a" << true << 2 << false << false;
+ QTest::newRow("[\\b]") << "\\b" << true << 2 << false << false;
+ QTest::newRow("[\\e]") << "\\e" << true << 2 << false << false;
+ QTest::newRow("[\\f]") << "\\f" << true << 2 << false << false;
+ QTest::newRow("[\\n]") << "\\n" << true << 2 << false << false;
+ QTest::newRow("[\\r]") << "\\r" << true << 2 << false << false;
+ QTest::newRow("[\\t]") << "\\t" << true << 2 << false << false;
+ QTest::newRow("[\\v]") << "\\v" << true << 2 << false << false;
+ QTest::newRow("[\\?]") << "\\?" << true << 2 << false << false;
+ QTest::newRow("[\\']") << "\\'" << true << 2 << false << false;
+ QTest::newRow("[\\\"]") << "\\\"" << true << 2 << false << false;
+ QTest::newRow("[\\\\]") << "\\\\" << true << 2 << false << false;
+ QTest::newRow("[\\c]") << "\\c" << false << 0 << true << false;
+ QTest::newRow("[x]") << "x" << false << 0 << true << false;
+ QTest::newRow("[ ]") << " " << false << 0 << true << false;
+ QTest::newRow("[a]") << "x" << false << 0 << true << false;
+ QTest::newRow("[r]") << "r" << false << 0 << true << false;
+ QTest::newRow("[//]") << "//" << false << 0 << true << false;
+
+ // Octal values
+ QTest::newRow("[\\1]") << "\\1" << true << 2 << false << false;
+ QTest::newRow("[\\12]") << "\\12" << true << 3 << false << false;
+ QTest::newRow("[\\123]") << "\\123" << true << 4 << false << false;
+ QTest::newRow("[\\1234]") << "\\1234" << true << 4 << false << false;
+ QTest::newRow("[\\123x]") << "\\123x" << true << 4 << false << false;
+
+ // Hex values
+ QTest::newRow("[\\xa]") << "\\xa" << true << 3 << false << false;
+ QTest::newRow("[\\xA]") << "\\xA" << true << 3 << false << false;
+ QTest::newRow("[\\Xa]") << "\\Xa" << false << 0 << true << false;
+ QTest::newRow("[\\xA10]") << "\\xA10" << true << 5 << false << false;
+ QTest::newRow("[\\xA0123456789]") << "\\xA0123456789" << true << 13 << false << false;
+ QTest::newRow("[\\xABCDEF]") << "\\xABCDEF" << true << 8 << false << false;
+ QTest::newRow("[\\xABCDEFGHI]") << "\\xABCDEFGHI" << true << 8 << false << false;
+}
+
+void tst_SpecificRules::testCChar()
+{
+ HlCCharRule rule;
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testCChar_data()
+{
+ addCommonColumns();
+
+ // Escape sequences
+ QTest::newRow("[\'\\a\']") << "\'\\a\'" << true << 4 << false << false;
+ QTest::newRow("[\'\\b\']") << "\'\\b\'" << true << 4 << false << false;
+ QTest::newRow("[\'\\e\']") << "\'\\e\'" << true << 4 << false << false;
+ QTest::newRow("[\'\\f\']") << "\'\\f\'" << true << 4 << false << false;
+ QTest::newRow("[\'\\n\']") << "\'\\n\'" << true << 4 << false << false;
+ QTest::newRow("[\'\\r\']") << "\'\\r\'" << true << 4 << false << false;
+ QTest::newRow("[\'\\t\']") << "\'\\t\'" << true << 4 << false << false;
+ QTest::newRow("[\'\\v\']") << "\'\\v\'" << true << 4 << false << false;
+ QTest::newRow("[\'\\?\']") << "\'\\?\'" << true << 4 << false << false;
+ QTest::newRow("[\'\\'\']") << "\'\\'\'" << true << 4 << false << false;
+ QTest::newRow("[\'\\\"\']") << "\'\\\"\'" << true << 4 << false << false;
+ QTest::newRow("[\'\\\\\']") << "\'\\\\\'" << true << 4 << false << false;
+ QTest::newRow("[\'\\c\']") << "\'\\c\'" << false << 0 << true << false;
+ QTest::newRow("[x]") << "x" << false << 0 << true << false;
+ QTest::newRow("[ ]") << " " << false << 0 << true << false;
+ QTest::newRow("[a]") << "x" << false << 0 << true << false;
+ QTest::newRow("[r]") << "r" << false << 0 << true << false;
+ QTest::newRow("[//]") << "//" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::testRangeDetect()
+{
+ QFETCH(QString, c);
+ QFETCH(QString, c1);
+ RangeDetectRule rule;
+ rule.setChar(c);
+ rule.setChar1(c1);
+
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testRangeDetect_data()
+{
+ QTest::addColumn<QString>("c");
+ QTest::addColumn<QString>("c1");
+ addCommonColumns();
+
+ QTest::newRow("[<>] against [<QString>]") << "<" << ">" << "<QString>"
+ << true << 9 << false << false;
+ QTest::newRow("[<>] against <x>") << "<" << ">" << "<x>" << true << 3 << false << false;
+ QTest::newRow("[<>] against < >") << "<" << ">" << "< >" << true << 5 << false << false;
+ QTest::newRow("[<>] against <x>abc") << "<" << ">" << "<x>abc" << true << 3 << false << false;
+ QTest::newRow("[<>] against <x> ") << "<" << ">" << "<x> " << true << 3 << false << false;
+ QTest::newRow("[<>] against abc") << "<" << ">" << "abc" << false << 0 << true << false;
+ QTest::newRow("[<>] against <abc") << "<" << ">" << "<abc" << false << 0 << true << false;
+ QTest::newRow("[<>] against abc<") << "<" << ">" << "abc<" << false << 0 << true << false;
+ QTest::newRow("[<>] against a<bc") << "<" << ">" << "a<bc" << false << 0 << true << false;
+ QTest::newRow("[<>] against abc<") << "<" << ">" << "abc<" << false << 0 << true << false;
+ QTest::newRow("[\"\"] against \"test.h\"") << "\"" << "\"" << "\"test.h\""
+ << true << 8 << false << false;
+}
+
+void tst_SpecificRules::testLineContinue()
+{
+ LineContinueRule rule;
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testLineContinue_data()
+{
+ addCommonColumns();
+
+ QTest::newRow("\\") << "\\" << true << 1 << false << true;
+ QTest::newRow("\\\\") << "\\\\" << false << 0 << true << false;
+ QTest::newRow("\\x") << "\\x" << false << 0 << true << false;
+ QTest::newRow("x\\") << "x\\" << false << 0 << true << false;
+ QTest::newRow("x") << "x" << false << 0 << true << false;
+ QTest::newRow("/") << "/" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::testDetectSpaces()
+{
+ DetectSpacesRule rule;
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testDetectSpaces_data()
+{
+ addCommonColumns();
+
+ QTest::newRow(" ") << " " << true << 1 << true << false;
+ QTest::newRow(" ") << " " << true << 4 << true << false;
+ QTest::newRow("\t") << "\t" << true << 1 << true << false;
+ QTest::newRow("x") << "x" << false << 0 << true << false;
+ QTest::newRow("#") << "#" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::testDetectIdentifier()
+{
+ DetectIdentifierRule rule;
+ testMatch(rule);
+}
+
+void tst_SpecificRules::testDetectIdentifier_data()
+{
+ addCommonColumns();
+
+ QTest::newRow("name") << "name" << true << 4 << false << false;
+ QTest::newRow("x") << "x" << true << 1 << false << false;
+ QTest::newRow("x1") << "x1" << true << 2 << false << false;
+ QTest::newRow("1x") << "1x" << false << 0 << true << false;
+ QTest::newRow("_x") << "_x" << true << 2 << false << false;
+ QTest::newRow("___x") << "___x" << true << 4 << false << false;
+ QTest::newRow("-x") << "-x" << false << 0 << true << false;
+ QTest::newRow("@x") << "@x" << false << 0 << true << false;
+ QTest::newRow("+x") << "+x" << false << 0 << true << false;
+ QTest::newRow("#x") << "#x" << false << 0 << true << false;
+ QTest::newRow("x_x") << "x_x" << true << 3 << false << false;
+ QTest::newRow("x1x") << "x1x" << true << 3 << false << false;
+ QTest::newRow("x#x") << "x#x" << true << 1 << false << false;
+ QTest::newRow("x-x") << "x-x" << true << 1 << false << false;
+ QTest::newRow("abc_") << "abc_" << true << 4 << false << false;
+ QTest::newRow("abc____") << "abc____" << true << 7 << false << false;
+ QTest::newRow("abc-") << "abc-" << true << 3 << false << false;
+ QTest::newRow("abc$") << "abc$" << true << 3 << false << false;
+}
+
+QTEST_MAIN(tst_SpecificRules)
+#include "tst_specificrules.moc"
DEFINES+=QTCREATOR_UTILS_STATIC_LIB QML_BUILD_STATIC_LIB QTCREATOR_TEST
DEFINES+=QTCREATORDIR=\\\"$$CREATORDIR\\\"
+DEFINES+=QT_CREATOR
DEPENDPATH += ..
DEPENDPATH += $$CREATORDIR/src/plugins/qmldesigner/designercore/include
using namespace CPlusPlus;
-class ForEachNode: protected ASTVisitor
-{
- Document::Ptr doc;
- AST *pattern;
-
-public:
- ForEachNode(Document::Ptr doc)
- : ASTVisitor(doc->translationUnit()),
- matcher() {}
-
- void operator()() { accept(doc->translationUnit()->ast()); }
-
-protected:
- using ASTVisitor::visit;
-
- virtual bool preVisit(AST *ast)
- {
- ir.reset();
- IfStatementAST *pattern = ir.IfStatement(ir.SimpleName());
-
- //CompoundStatementAST *pattern = ir.CompoundStatement();
-
- if (ast->match(ast, pattern, &matcher))
- translationUnit()->warning(ast->firstToken(), "matched");
-
- return true;
- }
-
-
- ASTPatternBuilder ir;
- ASTMatcher matcher;
-};
-
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
doc->control()->setDiagnosticClient(0);
doc->setSource(source);
doc->parse();
-
- ForEachNode forEachNode(doc);
- forEachNode();
}
return EXIT_SUCCESS;
#include <QtCore/QPointer>
#include <QtCore/QString>
#include <QtCore/QStringList>
+#include <QtCore/QSettings>
#include <QtCore/QStack>
#include <QtCore/QThread>
#include <QtCore/QVariant>
#include <string>
#include <vector>
-#if defined(__GNUC__)
+#if defined(__GNUC__) && !defined(__llvm__)
# define USE_GCC_EXT 1
# include <hash_set>
#endif
struct { int i; int b; };
struct { float f; };
double d;
- } a = { 42, 43 };
+ } a = { { 42, 43 } };
a.i = 1; // Break here. Expand a. Step.
a.i = 2; // Change a.i in Locals view to 0. This changes f, d but expectedly not b. Step.
a.i = 3; // Continue.
#endif
}
-void testFunctionPointer()
+typedef void (*func_t)();
+func_t testFunctionPointer()
{
- typedef void (*func_t)();
func_t f1 = testAnonymous;
- func_t f2 = testFunctionPointer;
- func_t f3 = testFunctionPointer;
+ func_t f2 = testPeekAndPoke3;
+ func_t f3 = testPeekAndPoke3;
Q_UNUSED(f1);
Q_UNUSED(f2);
Q_UNUSED(f3);
+ return f1;
}
-void testQByteArray()
+QByteArray testQByteArray()
{
QByteArray ba = "Hello";
ba += '"';
ba += char(0);
ba += 1;
ba += 2;
+ return ba;
}
static void throwit1()
return gotit;
}
-void testQDateTime()
+QDateTime testQDateTime()
{
QDateTime date;
date = QDateTime::currentDateTime();
date = date.addSecs(5);
date = date.addSecs(5);
date = date.addSecs(5);
+ return date;
}
-void testQFileInfo()
+QFileInfo testQFileInfo()
{
QFileInfo fi("/tmp/t");
QString s = fi.absoluteFilePath();
s = fi.bundleName();
s = fi.bundleName();
s = fi.bundleName();
+ return fi;
}
-void testQHash()
+QHash<int, float> testQHash()
{
#if 1
QHash<int, float> hgg0;
hash.insert("Welt", QPointer<QObject>(&ob));
hash.insert(".", QPointer<QObject>(&ob));
#endif
+ return hgg0;
}
void testQImage()
{
QApplication app(argc, argv);
#if 1
+ QPixmap pm;
Names::Bar::TestObject test;
QAction act("xxx", &app);
#endif
#if 1
- QObject ob(&app);
+ QWidget ob;
ob.setObjectName("An Object");
+ ob.setProperty("USER DEFINED 1", 44);
+ ob.setProperty("USER DEFINED 2", QStringList() << "FOO" << "BAR");
QObject ob1;
ob1.setObjectName("Another Object");
QObject::connect(&ob, SIGNAL(destroyed()), &ob1, SLOT(deleteLater()));
- QObject::connect(&app, SIGNAL(lastWindowClosed()), &ob, SLOT(deleteLater()));
+ //QObject::connect(&app, SIGNAL(lastWindowClosed()), &ob, SLOT(deleteLater()));
#endif
-#if 1
+#if 0
QList<QObject *> obs;
obs.append(&ob);
obs.append(&ob1);
ob1.setObjectName("A Subobject");
#endif
-#if 1
+#if 0
QString str = QString::fromUtf8("XXXXXXXXXXXXXXyyXXX ö");
QLabel l(str);
l.setObjectName("Some Label");
l.show();
-#endif
app.exec();
+#endif
}
void testQPixmap()
{
//Employee e1(1, "Herbert");
//Employee e2 = e1;
-
+#if 0
QSharedPointer<int> iptr(new int(43));
QSharedPointer<int> iptr2 = iptr;
QSharedPointer<int> iptr3 = iptr;
QWeakPointer<QString> wptr(ptr);
QWeakPointer<QString> wptr2 = wptr;
QWeakPointer<QString> wptr3 = wptr;
+#endif
+
+ QSharedPointer<Foo> fptr(new Foo(1));
+ QWeakPointer<Foo> wfptr(fptr);
+ QWeakPointer<Foo> wfptr2 = wfptr;
+ QWeakPointer<Foo> wfptr3 = wfptr;
}
#endif
#endif
}
-void testStdList()
+std::list<int> testStdList()
{
std::list<int> big;
for (int i = 0; i < 10000; ++i)
vec.push_back(true);
vec.push_back(false);
#endif
+ return big;
}
void testStdMap()
#endif
}
-void testStdSet()
+std::set<int> testStdSet()
{
std::set<int> hgg0;
hgg0.insert(11);
std::set<QPointer<QObject> > hash;
QPointer<QObject> ptr(&ob);
#endif
+ return hgg0;
}
-void testStdStack()
+std::stack<int> testStdStack()
{
std::stack<int *> plist1;
plist1.push(new int(1));
std::stack<Foo> flist;
flist.push(1);
flist.push(2);
+
+ return flist2;
}
-void testStdString()
+std::string testStdString()
{
QString foo;
std::string str;
v.push_back(str);
v.push_back(str);
v.push_back(str);
+
+ return str;
}
-void testStdVector()
+std::vector<int> testStdVector()
{
std::vector<int *> plist1;
plist1.push_back(new int(1));
std::vector<bool> vec;
vec.push_back(true);
vec.push_back(false);
+
+ return flist2;
}
void testQStandardItemModel()
QStandardItem *i1, *i2, *i11;
m.appendRow(QList<QStandardItem *>()
<< (i1 = new QStandardItem("1")) << (new QStandardItem("a")) << (new QStandardItem("a2")));
+ QModelIndex mi = i1->index();
m.appendRow(QList<QStandardItem *>()
<< (i2 = new QStandardItem("2")) << (new QStandardItem("b")));
i1->appendRow(QList<QStandardItem *>()
++i;
}
-void testQStack()
+QStack<int> testQStack()
{
QVector<int> bigv;
for (int i = 0; i < 10; ++i)
QStack<bool> vec;
vec.append(true);
vec.append(false);
+ return big;
}
void testQString()
{
QUrl url(QString("http://www.nokia.com"));
+ QImage im;
+ // Could be broken due to Return Value Optimzation
QString str = "Hello ";
str += " big, ";
str += " fat ";
delete pstring;
}
-void testQStringList()
+QStringList testQStringList()
{
QStringList l;
l << "Hello ";
l << " fat ";
l.takeFirst();
l << " World ";
+ return l;
}
-void testStruct()
+Foo testStruct()
{
Foo f(2);
f.doit();
f.doit();
f.doit();
+ return f;
}
class Thread : public QThread
void run()
{
+ int j = 2;
+ ++j;
for (int i = 0; i != 100000; ++i) {
//sleep(1);
std::cerr << m_id;
}
+ std::cerr << j;
}
private:
v = 1.0;
v = "string";
v = QRect(100, 200, 300, 400);
+ v = QRectF(100, 200, 300, 400);
v = 1;
+ //return v;
}
-void testQVariant2()
+QVariant testQVariant2()
{
QVariant value;
QVariant::Type t = QVariant::String;
var.setValue(my);
var.setValue(my);
#endif
+ return QVariant("sss");
}
-void testQVariant3()
+QVariant testQVariant3()
{
QVariantList vl;
vl.append(QVariant(1));
QVariant variant = qVariantFromValue(list);
list.clear();
list = qVariantValue<QList<int> >(variant);
+ return QVariant("xxx");
}
-void testQVector()
+QVector<int> testQVector()
{
QVector<int> big(10000);
QVector<bool> vec;
vec.append(true);
vec.append(false);
+
+ return big;
}
-void testQVectorOfQList()
+QVector<QList<int> > testQVectorOfQList()
{
QVector<QList<int> > v;
QVector<QList<int> > *pv = &v;
v.append(QList<int>() << 1);
v.append(QList<int>() << 2 << 3);
Q_UNUSED(pv);
+ return v;
}
void testPointer()
{
Foo *f = new Foo();
+ Q_UNUSED(f);
int i = 0;
++i;
++i;
return a.size() + b.size() + c.size();
}
+struct Color
+{
+ int r,g,b,a;
+ Color() { r = 1, g = 2, b = 3, a = 4; }
+};
+
+Color testColor()
+{
+ Color c;
+ c.r = 5;
+ return c;
+}
+
+int fooii()
+{
+ return 3;
+}
+
+typedef QVector<Foo> FooVector;
+
+FooVector fooVector()
+{
+ FooVector f;
+ f.append(Foo(2));
+ fprintf(stderr, "xxx\n");
+ f.append(Foo(3));
+ f.append(Foo(4));
+ for (int i = 0; i < 1000; ++i)
+ f.append(Foo(i));
+ return f;
+}
+
+void testStuff()
+{
+ FooVector const &f = fooVector();
+ int i = f.size();
+ Q_UNUSED(i);
+}
+
void testPassByReferenceHelper(Foo &f)
{
++f.a;
testPassByReferenceHelper(f);
}
+void testWCout()
+{
+ using namespace std;
+ wstring x = L"xxxxx";
+ wstring::iterator i = x.begin();
+ while (i != x.end()) {
+ wcout << *i;
+ i++;
+ }
+ wcout.flush();
+ string y = "yyyyy";
+ string::iterator j = y.begin();
+ while (j != y.end()) {
+ cout << *j;
+ j++;
+ }
+ cout.flush();
+};
+
+void testWCout0()
+{
+ // Mixing cout and wcout does not work with gcc.
+ // See http://gcc.gnu.org/ml/gcc-bugs/2006-05/msg01193.html
+ // which also says "you can obtain something close to your
+ // expectations by calling std::ios::sync_with_stdio(false);
+ // at the beginning of your program."
+
+ using namespace std;
+ //std::ios::sync_with_stdio(false);
+ wcout << L"WWWWWW" << endl;
+ wcerr << L"YYYYYY" << endl;
+ cout << "CCCCCC" << endl;
+ cerr << "EEEEEE" << endl;
+ wcout << L"WWWWWW" << endl;
+ wcerr << L"YYYYYY" << endl;
+ cout << "CCCCCC" << endl;
+ cerr << "EEEEEE" << endl;
+ wcout << L"WWWWWW" << endl;
+ wcerr << L"YYYYYY" << endl;
+ cout << "CCCCCC" << endl;
+ cerr << "EEEEEE" << endl;
+}
+
+void testQSettings()
+{
+ // Note: Construct a QCoreApplication first.
+ QSettings settings("/tmp/test.ini", QSettings::IniFormat);
+ QVariant value = settings.value("item1","").toString();
+ int x = 1;
+ Q_UNUSED(x);
+}
+
int main(int argc, char *argv[])
{
+ //testQSettings();
+ //testWCout0();
+ //testWCout();
+ testColor();
+ testStuff();
testPeekAndPoke3();
testFunctionPointer();
testAnonymous();
testPlugin();
testQList();
testQLinkedList();
- char *s = "aöa";
- wchar_t *w = L"aöa";
+ const char *s = "aöa";
+ const wchar_t *w = L"aöa";
testNamespace();
//return 0;
testQHash();
testQMultiMap();
testQString();
testQSet();
- #if QT_VERSION >= 0x040500
+# if QT_VERSION >= 0x040500
testQSharedPointer();
- #endif
+# endif
testQStringList();
testStruct();
- //testThreads();
+ testQThread();
testQVariant1();
testQVariant2();
testQVariant3();
TARGET = debuggertest
DEPENDPATH += .
INCLUDEPATH += .
-DESTDIR = ..
+DESTDIR = .
# Input
-SOURCES += ../app.cpp
+SOURCES += app.cpp
-# SOURCES += ../../../../../share/qtcreator/gdbmacros/gdbmacros.cpp
+# SOURCES += ../../../share/qtcreator/gdbmacros/gdbmacros.cpp
QT += network
message("this says <foo & bar>")
TEMPLATE = lib
TARGET = plugin
-DESTDIR = ..
+DESTDIR = .
CONFIG += shared
-SOURCES += ../plugin.cpp
+SOURCES += plugin.cpp
macx {
QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../PlugIns/$${PROVIDER}/
TEMPLATE = subdirs
-SUBDIRS += app plugin
+SUBDIRS += app.pro plugin.pro