From 6445c99ad2020182b5d105b29e373de6273cb5f5 Mon Sep 17 00:00:00 2001 From: Patricia Santana Cruz <patriciasc@openismus.com> Date: Tue, 29 Nov 2011 14:19:28 +0100 Subject: [PATCH] Add AutotoolsProjectManager plugin Change-Id: Icbc8d105a3ffea2bf705d18e3413f6b3487ccfd3 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com> Reviewed-by: hjk <qthjk@ovi.com> Reviewed-by: Leena Miettinen <riitta-leena.miettinen@nokia.com> --- doc/images/qtcreator-autotools-buildrun.png | Bin 0 -> 25725 bytes .../qtcreator-autotools-buildsettings.png | Bin 0 -> 16596 bytes .../projects/creator-projects-autotools.qdoc | 77 +++ doc/src/projects/creator-projects-cmake.qdoc | 2 +- .../projects/creator-projects-generic.qdoc | 2 +- doc/src/qtcreator.qdoc | 1 + .../generic-highlighter/autoconf.xml | 390 +++++++++++++ .../AutotoolsProject.mimetypes.xml | 8 + .../AutotoolsProjectManager.pluginspec.in | 23 + .../autotoolsprojectmanager/autogenstep.cpp | 305 ++++++++++ .../autotoolsprojectmanager/autogenstep.h | 162 ++++++ .../autoreconfstep.cpp | 299 ++++++++++ .../autotoolsprojectmanager/autoreconfstep.h | 163 ++++++ .../autotoolsbuildconfiguration.cpp | 260 +++++++++ .../autotoolsbuildconfiguration.h | 94 +++ .../autotoolsbuildsettingswidget.cpp | 139 +++++ .../autotoolsbuildsettingswidget.h | 88 +++ .../autotoolsmanager.cpp | 83 +++ .../autotoolsmanager.h | 65 +++ .../autotoolsopenprojectwizard.cpp | 121 ++++ .../autotoolsopenprojectwizard.h | 87 +++ .../autotoolsproject.cpp | 542 ++++++++++++++++++ .../autotoolsproject.h | 183 ++++++ .../autotoolsproject.qrc | 5 + .../autotoolsprojectconstants.h | 58 ++ .../autotoolsprojectfile.cpp | 109 ++++ .../autotoolsprojectfile.h | 82 +++ .../autotoolsprojectmanager.pro | 39 ++ .../autotoolsprojectmanager_dependencies.pri | 3 + .../autotoolsprojectnode.cpp | 123 ++++ .../autotoolsprojectnode.h | 93 +++ .../autotoolsprojectplugin.cpp | 85 +++ .../autotoolsprojectplugin.h | 84 +++ .../autotoolstarget.cpp | 186 ++++++ .../autotoolsprojectmanager/autotoolstarget.h | 101 ++++ .../autotoolsprojectmanager/configurestep.cpp | 303 ++++++++++ .../autotoolsprojectmanager/configurestep.h | 162 ++++++ .../makefileparser.cpp | 454 +++++++++++++++ .../autotoolsprojectmanager/makefileparser.h | 231 ++++++++ .../makefileparserthread.cpp | 112 ++++ .../makefileparserthread.h | 136 +++++ .../autotoolsprojectmanager/makestep.cpp | 326 +++++++++++ .../autotoolsprojectmanager/makestep.h | 163 ++++++ .../genericprojectwizard.cpp | 2 +- src/plugins/plugins.pro | 6 + 45 files changed, 5954 insertions(+), 3 deletions(-) create mode 100644 doc/images/qtcreator-autotools-buildrun.png create mode 100644 doc/images/qtcreator-autotools-buildsettings.png create mode 100644 doc/src/projects/creator-projects-autotools.qdoc create mode 100644 share/qtcreator/generic-highlighter/autoconf.xml create mode 100644 src/plugins/autotoolsprojectmanager/AutotoolsProject.mimetypes.xml create mode 100644 src/plugins/autotoolsprojectmanager/AutotoolsProjectManager.pluginspec.in create mode 100644 src/plugins/autotoolsprojectmanager/autogenstep.cpp create mode 100644 src/plugins/autotoolsprojectmanager/autogenstep.h create mode 100644 src/plugins/autotoolsprojectmanager/autoreconfstep.cpp create mode 100644 src/plugins/autotoolsprojectmanager/autoreconfstep.h create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsbuildconfiguration.cpp create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsbuildconfiguration.h create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsbuildsettingswidget.cpp create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsbuildsettingswidget.h create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsmanager.cpp create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsmanager.h create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsopenprojectwizard.cpp create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsopenprojectwizard.h create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsproject.cpp create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsproject.h create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsproject.qrc create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsprojectconstants.h create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsprojectfile.cpp create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsprojectfile.h create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsprojectmanager.pro create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsprojectmanager_dependencies.pri create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsprojectnode.cpp create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsprojectnode.h create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.cpp create mode 100644 src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.h create mode 100644 src/plugins/autotoolsprojectmanager/autotoolstarget.cpp create mode 100644 src/plugins/autotoolsprojectmanager/autotoolstarget.h create mode 100644 src/plugins/autotoolsprojectmanager/configurestep.cpp create mode 100644 src/plugins/autotoolsprojectmanager/configurestep.h create mode 100644 src/plugins/autotoolsprojectmanager/makefileparser.cpp create mode 100644 src/plugins/autotoolsprojectmanager/makefileparser.h create mode 100644 src/plugins/autotoolsprojectmanager/makefileparserthread.cpp create mode 100644 src/plugins/autotoolsprojectmanager/makefileparserthread.h create mode 100644 src/plugins/autotoolsprojectmanager/makestep.cpp create mode 100644 src/plugins/autotoolsprojectmanager/makestep.h diff --git a/doc/images/qtcreator-autotools-buildrun.png b/doc/images/qtcreator-autotools-buildrun.png new file mode 100644 index 0000000000000000000000000000000000000000..05ef57900b4abeed597f4f6ab62f5719dcb78823 GIT binary patch literal 25725 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 NLseU)Qpqy>e*m_ODewRQ literal 0 HcmV?d00001 diff --git a/doc/images/qtcreator-autotools-buildsettings.png b/doc/images/qtcreator-autotools-buildsettings.png new file mode 100644 index 0000000000000000000000000000000000000000..d82b4c591f4911b6f6e580e1b8578ca51c6068ab GIT binary patch literal 16596 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 literal 0 HcmV?d00001 diff --git a/doc/src/projects/creator-projects-autotools.qdoc b/doc/src/projects/creator-projects-autotools.qdoc new file mode 100644 index 00000000000..449a7aa52ba --- /dev/null +++ b/doc/src/projects/creator-projects-autotools.qdoc @@ -0,0 +1,77 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasc@openismus.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +/*! + \contentspage index.html + \previouspage creator-project-cmake.html + \page creator-projects-autotools.html + \nextpage creator-project-generic.html + + \title Setting Up an Autotools Project + The AutotoolsProjectManager is a plugin for autotools support. + + \image qtcreator-autotools-buildrun.png + + \image qtcreator-autotools-buildsettings.png + + \section1 Opening and Using Autotools Projects + + To work with your Autotools project in \QC: + + \list 1 + + \o Select \gui{File > Open File or Project}. + \o Select the Makefile.am from your project. This is the only way a + user can use the autotools plugin. Thus, a Makefile.am must + always exist before hand. + \o Select the build directory. Only in-source building is working + right now. + \o Select \gui Finish. + \QC displays the project tree structure. The root node displays + the project name. All project files are listed below it and you + can open them from the list. + \o Select \gui Run to build and run the application. This will + execute autogen.sh or autoreconf, configure and make. The first + time, when running the application, a dialog will ask you to + choose the executable's location, then, \QC will remember it for + the following times. Ideally, this will be changed in the future, + to be done in a more automated way. + \o To check and edit autotools build steps, select + \gui{Projects > Build Settings}. You can see the typical + autotools build steps: autogen.sh/autoreconf, configure and make. + You may configure some parameters such as adding new configure + parameters or changing the build directory (though, as mentiond + before, only in-source building is working at the moment). + \endlist +*/ diff --git a/doc/src/projects/creator-projects-cmake.qdoc b/doc/src/projects/creator-projects-cmake.qdoc index 2dd7ff90f30..a1471be9c57 100644 --- a/doc/src/projects/creator-projects-cmake.qdoc +++ b/doc/src/projects/creator-projects-cmake.qdoc @@ -29,7 +29,7 @@ \contentspage index.html \previouspage creator-project-wizards.html \page creator-project-cmake.html - \nextpage creator-project-generic.html + \nextpage creator-projects-autotools.html \title Setting Up a CMake Project diff --git a/doc/src/projects/creator-projects-generic.qdoc b/doc/src/projects/creator-projects-generic.qdoc index 671e4248b2f..51fd14dee1e 100644 --- a/doc/src/projects/creator-projects-generic.qdoc +++ b/doc/src/projects/creator-projects-generic.qdoc @@ -27,7 +27,7 @@ /*! \contentspage index.html - \previouspage creator-project-cmake.html + \previouspage creator-projects-autotools.html \page creator-project-generic.html \nextpage creator-version-control.html diff --git a/doc/src/qtcreator.qdoc b/doc/src/qtcreator.qdoc index 1b1f250dece..84f7ede9dbf 100644 --- a/doc/src/qtcreator.qdoc +++ b/doc/src/qtcreator.qdoc @@ -163,6 +163,7 @@ \o \l{Supported Platforms} \o \l{Adding New Custom Wizards} \o \l{Setting Up a CMake Project} + \o \l{Setting Up an Autotools Project} \o \l{Setting Up a Generic Project} \o \l{Using Version Control Systems} \o \l{Adding Qt Designer Plugins} diff --git a/share/qtcreator/generic-highlighter/autoconf.xml b/share/qtcreator/generic-highlighter/autoconf.xml new file mode 100644 index 00000000000..36498527a25 --- /dev/null +++ b/share/qtcreator/generic-highlighter/autoconf.xml @@ -0,0 +1,390 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE language SYSTEM "language.dtd"> +<!-- (c) 2008-2011 by Jürgen Heinemann http://www.hjcms.de + @see http://www.gnu.org/software/automake/manual/autoconf/ +--> +<language name="Autoconf Language" version="1.10" kateversion="2.4" section="Other" extensions="configure.ac;configure.in;configure.in.in;*.m4;*.M4" mimetype="text/x-m4;text/x-autoconf" author="Juergen Heinemann (nospam@hjcms.de)" license="LGPL"> + <highlighting> + <!-- http://www.gnu.org/software/automake/manual/autoconf/Program-_0026-Function-Index.html --> + <list name="keywords"> + <item> if </item> + <item> then </item> + <item> elif </item> + <item> else </item> + <item> fi </item> + <item> for </item> + <item> in </item> + <item> do </item> + <item> don </item> + <item> function </item> + <item> select </item> + <item> until </item> + <item> while </item> + <item> set </item> + <item> ifelse </item> + <item> case </item> + <item> esac </item> + </list> + + <!-- http://www.gnu.org/software/automake/manual/autoconf/Limitations-of-Builtins.html --> + <list name="builtins"> + <item> : </item> + <item> source </item> + <item> alias </item> + <item> bg </item> + <item> bind </item> + <item> break </item> + <item> builtin </item> + <item> cd </item> + <item> caller </item> + <item> command </item> + <item> compgen </item> + <item> complete </item> + <item> continue </item> + <item> dirs </item> + <item> disown </item> + <item> echo </item> + <item> enable </item> + <item> eval </item> + <item> exec </item> + <item> exit </item> + <item> fc </item> + <item> fg </item> + <item> getopts </item> + <item> hash </item> + <item> help </item> + <item> history </item> + <item> jobs </item> + <item> kill </item> + <item> let </item> + <item> logout </item> + <item> popd </item> + <item> printf </item> + <item> pushd </item> + <item> pwd </item> + <item> return </item> + <item> set </item> + <item> shift </item> + <item> shopt </item> + <item> suspend </item> + <item> test </item> + <item> time </item> + <item> times </item> + <item> trap </item> + <item> type </item> + <item> ulimit </item> + <item> umask </item> + <item> unalias </item> + <item> wait </item> + </list> + + <list name="bools"> + <item> no </item> + <item> yes </item> + <item> false </item> + <item> true </item> + </list> + + <!-- + This is an alphabetical list of the M4, M4sugar, and M4sh macros. + http://www.gnu.org/software/automake/manual/autoconf/M4-Macro-Index.html + --> + <list name="m4sugar"> + <item> AS_BOURNE_COMPATIBLE </item> + <item> AS_BOX </item> + <item> AS_CASE </item> + <item> AS_DIRNAME </item> + <item> AS_ECHO </item> + <item> AS_ECHO_N </item> + <item> AS_ESCAPE </item> + <item> AS_EXIT </item> + <item> AS_HELP_STRING </item> + <item> AS_IF </item> + <item> AS_INIT </item> + <item> AS_INIT_GENERATED </item> + <item> AS_LINENO_PREPARE </item> + <item> AS_LITERAL_IF </item> + <item> AS_LITERAL_WORD_IF </item> + <item> AS_ME_PREPARE </item> + <item> AS_MESSAGE_FD </item> + <item> AS_MESSAGE_LOG_FD </item> + <item> AS_MKDIR_P </item> + <item> AS_ORIGINAL_STDIN_FD </item> + <item> AS_SET_CATFILE </item> + <item> AS_SET_STATUS </item> + <item> AS_SHELL_SANITIZE </item> + <item> AS_TMPDIR </item> + <item> AS_TR_CPP </item> + <item> AS_TR_SH </item> + <item> AS_UNSET </item> + <item> AS_VAR_APPEND </item> + <item> AS_VAR_ARITH </item> + <item> AS_VAR_COPY </item> + <item> AS_VAR_IF </item> + <item> AS_VAR_POPDEF </item> + <item> AS_VAR_PUSHDEF </item> + <item> AS_VAR_SET </item> + <item> AS_VAR_SET_IF </item> + <item> AS_VAR_TEST_SET </item> + <item> AS_VERSION_COMPARE </item> + <item> m4_append </item> + <item> m4_append_uniq </item> + <item> m4_append_uniq_w </item> + <item> m4_apply </item> + <item> m4_argn </item> + <item> m4_assert </item> + <item> m4_bmatch </item> + <item> m4_bpatsubst </item> + <item> m4_bpatsubsts </item> + <item> m4_bregexp </item> + <item> m4_builtin </item> + <item> m4_car </item> + <item> m4_case </item> + <item> m4_cdr </item> + <item> m4_changecom </item> + <item> m4_changequote </item> + <item> m4_chomp </item> + <item> m4_chomp_all </item> + <item> m4_cleardivert </item> + <item> m4_cmp </item> + <item> m4_combine </item> + <item> m4_cond </item> + <item> m4_copy </item> + <item> m4_copy_force </item> + <item> m4_count </item> + <item> m4_curry </item> + <item> m4_debugfile </item> + <item> m4_debugmode </item> + <item> m4_decr </item> + <item> m4_default </item> + <item> m4_default_nblank </item> + <item> m4_default_nblank_quoted </item> + <item> m4_default_quoted </item> + <item> m4_define </item> + <item> m4_define_default </item> + <item> m4_defn </item> + <item> m4_divert </item> + <item> m4_divert_once </item> + <item> m4_divert_pop </item> + <item> m4_divert_push </item> + <item> m4_divert_text </item> + <item> m4_divnum </item> + <item> m4_do </item> + <item> m4_dquote </item> + <item> m4_dquote_elt </item> + <item> m4_dumpdef </item> + <item> m4_dumpdefs </item> + <item> m4_echo </item> + <item> m4_errprint </item> + <item> m4_errprintn </item> + <item> m4_escape </item> + <item> m4_esyscmd </item> + <item> m4_esyscmd_s </item> + <item> m4_eval </item> + <item> m4_exit </item> + <item> m4_expand </item> + <item> m4_fatal </item> + <item> m4_flatten </item> + <item> m4_for </item> + <item> m4_foreach </item> + <item> m4_foreach_w </item> + <item> m4_format </item> + <item> m4_if </item> + <item> m4_ifblank </item> + <item> m4_ifdef </item> + <item> m4_ifnblank </item> + <item> m4_ifndef </item> + <item> m4_ifset </item> + <item> m4_ifval </item> + <item> m4_ifvaln </item> + <item> m4_ignore </item> + <item> m4_include </item> + <item> m4_incr </item> + <item> m4_index </item> + <item> m4_indir </item> + <item> m4_init </item> + <item> m4_join </item> + <item> m4_joinall </item> + <item> m4_len </item> + <item> m4_list_cmp </item> + <item> m4_location </item> + <item> m4_make_list </item> + <item> m4_maketemp </item> + <item> m4_map </item> + <item> m4_map_args </item> + <item> m4_map_args_pair </item> + <item> m4_map_args_sep </item> + <item> m4_map_args_w </item> + <item> m4_map_sep </item> + <item> m4_mapall </item> + <item> m4_mapall_sep </item> + <item> m4_max </item> + <item> m4_min </item> + <item> m4_mkstemp </item> + <item> m4_n </item> + <item> m4_newline </item> + <item> m4_normalize </item> + <item> m4_pattern_allow </item> + <item> m4_pattern_forbid </item> + <item> m4_popdef </item> + <item> m4_pushdef </item> + <item> m4_quote </item> + <item> m4_re_escape </item> + <item> m4_rename </item> + <item> m4_rename_force </item> + <item> m4_reverse </item> + <item> m4_set_add </item> + <item> m4_set_add_all </item> + <item> m4_set_contains </item> + <item> m4_set_contents </item> + <item> m4_set_delete </item> + <item> m4_set_difference </item> + <item> m4_set_dump </item> + <item> m4_set_empty </item> + <item> m4_set_foreach </item> + <item> m4_set_intersection </item> + <item> m4_set_list </item> + <item> m4_set_listc </item> + <item> m4_set_map </item> + <item> m4_set_map_sep </item> + <item> m4_set_remove </item> + <item> m4_set_size </item> + <item> m4_set_union </item> + <item> m4_shift </item> + <item> m4_shift2 </item> + <item> m4_shift3 </item> + <item> m4_shiftn </item> + <item> m4_sign </item> + <item> m4_sinclude </item> + <item> m4_split </item> + <item> m4_stack_foreach </item> + <item> m4_stack_foreach_lifo </item> + <item> m4_stack_foreach_sep </item> + <item> m4_stack_foreach_sep_lifo </item> + <item> m4_strip </item> + <item> m4_substr </item> + <item> m4_syscmd </item> + <item> m4_sysval </item> + <item> m4_text_box </item> + <item> m4_text_wrap </item> + <item> m4_tolower </item> + <item> m4_toupper </item> + <item> m4_traceoff </item> + <item> m4_traceon </item> + <item> m4_translit </item> + <item> m4_undefine </item> + <item> m4_undivert </item> + <item> m4_unquote </item> + <item> m4_version_compare </item> + <item> m4_version_prereq </item> + <item> m4_warn </item> + <item> m4_wrap </item> + <item> m4_wrap_lifo </item> + </list> + + <!-- Autotest Macro Index --> + <list name="autotest_macro"> + <item> AT_ARG_OPTION </item> + <item> AT_ARG_OPTION_ARG </item> + <item> AT_BANNER </item> + <item> AT_CAPTURE_FILE </item> + <item> AT_CHECK </item> + <item> AT_CHECK_EUNIT </item> + <item> AT_CHECK_UNQUOTED </item> + <item> AT_CLEANUP </item> + <item> AT_COLOR_TESTS </item> + <item> AT_COPYRIGHT </item> + <item> AT_DATA </item> + <item> AT_FAIL_IF </item> + <item> AT_INIT </item> + <item> AT_KEYWORDS </item> + <item> AT_PACKAGE_BUGREPORT </item> + <item> AT_PACKAGE_NAME </item> + <item> AT_PACKAGE_STRING </item> + <item> AT_PACKAGE_TARNAME </item> + <item> AT_PACKAGE_URL </item> + <item> AT_PACKAGE_VERSION </item> + <item> AT_SETUP </item> + <item> AT_SKIP_IF </item> + <item> AT_TESTED </item> + <item> AT_XFAIL_IF </item> + </list> + + <list name="libtool"> + <item> LT_PREREQ </item> + <item> LT_LANG </item> + <item> LT_INIT </item> + <item> LTDL_INIT </item> + <item> LT_CONFIG_LTDL_DIR </item> + </list> + + <list name="pkgconfig"> + <item> PKG_CHECK_MODULES </item> + <item> PKG_PROG_PKG_CONFIG </item> + <item> PKG_CHECK_EXISTS </item> + </list> + + <contexts> + <context attribute="Normal Text" lineEndContext="#stay" name="Default"> + <!-- <IncludeRules context="##Bash" /> --> + <keyword attribute="Keyword" context="#stay" String="keywords"/> + <RegExpr attribute="Builtin" context="#stay" String="\.(?=\s)"/> + <keyword attribute="Builtin" context="#stay" String="builtins"/> + <keyword attribute="Boolean" context="#stay" String="bools"/> + <!-- Autoconf Macros --> + <keyword attribute="M4 Sugar Macros" context="#stay" String="m4sugar"/> + <!-- Autotest Macro Index --> + <keyword attribute="Autotest Macros" context="#stay" String="autotest_macro"/> + <!-- Other Macros --> + <keyword attribute="pkg-config Macros" context="#stay" String="pkgconfig"/> + <!-- libtool Macros --> + <keyword attribute="Libtool Macros" context="#stay" String="libtool"/> + <!-- Autoconf Macros --> + <RegExpr attribute="Autoconf Macros" context="#stay" String="\bAC_[A-Z0-9_]+\b" insensitive="false" endRegion="BeginRegion"/> + <!-- Automake Macros --> + <RegExpr attribute="Automake Macros" context="#stay" String="\bAM_[A-Z0-9_]+\b" insensitive="false" endRegion="BeginRegion"/> + <!-- Script temp Defined Macros --> + <RegExpr attribute="Inline Macros" context="#stay" String="\bac_[a-z_]+\b" insensitive="false" endRegion="BeginRegion"/> + <RegExpr attribute="Char" context="#stay" String="'.'"/> + <DetectChar attribute="String" context="String" char="""/> + <AnyChar attribute="Symbol" context="#stay" String=":!%&()+,-/.*<=>|"/> + <RegExpr attribute="Variable" context="#stay" String="\$[a-z_]+" insensitive="true" endRegion="BeginRegion"/> + <Float attribute="Float" context="#stay"/> + <Int attribute="Decimal" context="#stay"/> + <RegExpr attribute="Comment" context="#stay" String="(\bdnl|^#).*$" insensitive="true" endRegion="BeginRegion"/> + </context> + <context attribute="Region Marker" lineEndContext="#pop" name="Region Marker"/> + <context attribute="String" lineEndContext="#pop" name="String"> + <DetectChar attribute="String" context="#pop" char="""/> + </context> + </contexts> + <itemDatas> + <itemData name="Normal Text" defStyleNum="dsNormal"/> + <itemData name="Keyword" defStyleNum="dsKeyword"/> + <itemData name="Builtin" defStyleNum="dsKeyword" color="#808"/> + <itemData name="M4 Sugar Macros" defStyleNum="dsKeyword"/> + <itemData name="Autotest Macros" defStyleNum="dsKeyword"/> + <itemData name="Autoconf Macros" defStyleNum="dsKeyword" color="#0095ff" selColor="#ffffff" bold="1"/> + <itemData name="Automake Macros" defStyleNum="dsKeyword" color="#6666cc" selColor="#ffffff" bold="1"/> + <itemData name="Libtool Macros" defStyleNum="dsKeyword" color="#6666cc" selColor="#ffffff" bold="1"/> + <itemData name="Inline Macros" defStyleNum="dsKeyword" color="#6666cc" selColor="#ffffff"/> + <itemData name="pkg-config Macros" defStyleNum="dsKeyword"/> + <itemData name="Boolean" defStyleNum="dsOthers"/> + <itemData name="Variable" defStyleNum="dsOthers"/> + <itemData name="Decimal" defStyleNum="dsDecVal"/> + <itemData name="Float" defStyleNum="dsFloat"/> + <itemData name="Char" defStyleNum="dsChar"/> + <itemData name="String" defStyleNum="dsString"/> + <itemData name="Comment" defStyleNum="dsComment"/> + <itemData name="Symbol" defStyleNum="dsNormal"/> + <itemData name="Region Marker" defStyleNum="dsRegionMarker"/> + </itemDatas> + </highlighting> + <general> + <comments> + <comment name="singleLine" start="dnl"/> + <comment name="multiLine" start="/*" end="*/"/> + </comments> + <keywords casesensitive="0"/> + </general> +</language> diff --git a/src/plugins/autotoolsprojectmanager/AutotoolsProject.mimetypes.xml b/src/plugins/autotoolsprojectmanager/AutotoolsProject.mimetypes.xml new file mode 100644 index 00000000000..6e32748d2cf --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/AutotoolsProject.mimetypes.xml @@ -0,0 +1,8 @@ +<?xml version="1.0"?> +<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'> + <mime-type type="text/x-makefile"> + <sub-class-of type="text/plain"/> + <comment>Automake based Makefile</comment> + <glob weight="10" pattern="Makefile.am"/> + </mime-type> +</mime-info> diff --git a/src/plugins/autotoolsprojectmanager/AutotoolsProjectManager.pluginspec.in b/src/plugins/autotoolsprojectmanager/AutotoolsProjectManager.pluginspec.in new file mode 100644 index 00000000000..31bd06076a6 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/AutotoolsProjectManager.pluginspec.in @@ -0,0 +1,23 @@ +<plugin name=\"AutotoolsProjectManager\" version=\"$$QTCREATOR_VERSION\" compatVersion=\"$$QTCREATOR_VERSION\"> + <vendor>Openismus GmbH</vendor> + <copyright>(C) 2010 Openismus GmbH</copyright> + <license>GNU Lesser General Public License Usage + 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. + + In addition, as a special exception, Nokia gives you certain additional + rights. These rights are described in the Nokia Qt LGPL Exception + version 1.1, included in the file LGPL_EXCEPTION.txt in this package.</license> + <category>Build Systems</category> + <description>Autotools project integration.</description> + <url>http://qt.nokia.com</url> + <dependencyList> + <dependency name=\"Core\" version=\"$$QTCREATOR_VERSION\"/> + <dependency name=\"ProjectExplorer\" version=\"$$QTCREATOR_VERSION\"/> + <dependency name=\"CppTools\" version=\"$$QTCREATOR_VERSION\"/> + </dependencyList> +</plugin> diff --git a/src/plugins/autotoolsprojectmanager/autogenstep.cpp b/src/plugins/autotoolsprojectmanager/autogenstep.cpp new file mode 100644 index 00000000000..f5144e8d9c2 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autogenstep.cpp @@ -0,0 +1,305 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "autogenstep.h" +#include "autotoolsproject.h" +#include "autotoolstarget.h" +#include "autotoolsbuildconfiguration.h" +#include "autotoolsprojectconstants.h" + +#include <projectexplorer/buildsteplist.h> +#include <projectexplorer/toolchain.h> +#include <projectexplorer/gnumakeparser.h> +#include <projectexplorer/projectexplorer.h> +#include <projectexplorer/projectexplorerconstants.h> +#include <utils/qtcprocess.h> + +#include <QtCore/QVariantMap> +#include <QtCore/QDateTime> +#include <QtGui/QLineEdit> +#include <QtGui/QFormLayout> + +using namespace AutotoolsProjectManager; +using namespace AutotoolsProjectManager::Internal; +using namespace ProjectExplorer; + +namespace { +const char AUTOGEN_ADDITIONAL_ARGUMENTS_KEY[] = "AutotoolsProjectManager.AutogenStep.AdditionalArguments"; +const char AUTOGEN_STEP_ID[] = "AutotoolsProjectManager.AutogenStep"; +} + +///////////////////////////// +// AutogenStepFactory class +///////////////////////////// +AutogenStepFactory::AutogenStepFactory(QObject *parent) : + ProjectExplorer::IBuildStepFactory(parent) +{ +} + +AutogenStepFactory::~AutogenStepFactory() +{ +} + +QStringList AutogenStepFactory::availableCreationIds(BuildStepList *parent) const +{ + if (parent->target()->project()->id() == QLatin1String(Constants::AUTOTOOLS_PROJECT_ID)) + return QStringList() << QLatin1String(AUTOGEN_STEP_ID); + return QStringList(); +} + +QString AutogenStepFactory::displayNameForId(const QString &id) const +{ + if (id == QLatin1String(AUTOGEN_STEP_ID)) + return tr("Autogen", "Display name for AutotoolsProjectManager::AutogenStep id."); + return QString(); +} + +bool AutogenStepFactory::canCreate(BuildStepList *parent, const QString &id) const +{ + if (parent->target()->project()->id() != QLatin1String(Constants::AUTOTOOLS_PROJECT_ID)) + return false; + + if (parent->id() != ProjectExplorer::Constants::BUILDSTEPS_BUILD) + return false; + + return QLatin1String(AUTOGEN_STEP_ID) == id; +} + +BuildStep *AutogenStepFactory::create(BuildStepList *parent, const QString &id) +{ + if (!canCreate(parent, id)) + return 0; + return new AutogenStep(parent); +} + +bool AutogenStepFactory::canClone(BuildStepList *parent, BuildStep *source) const +{ + return canCreate(parent, source->id()); +} + +BuildStep *AutogenStepFactory::clone(BuildStepList *parent, BuildStep *source) +{ + if (!canClone(parent, source)) + return 0; + return new AutogenStep(parent, static_cast<AutogenStep *>(source)); +} + +bool AutogenStepFactory::canRestore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map) const +{ + QString id(ProjectExplorer::idFromMap(map)); + return canCreate(parent, id); +} + +BuildStep *AutogenStepFactory::restore(BuildStepList *parent, const QVariantMap &map) +{ + if (!canRestore(parent, map)) + return 0; + AutogenStep *bs = new AutogenStep(parent); + if (bs->fromMap(map)) + return bs; + delete bs; + return 0; +} + +//////////////////////// +// AutogenStep class +//////////////////////// +AutogenStep::AutogenStep(ProjectExplorer::BuildStepList *bsl) : + AbstractProcessStep(bsl, QLatin1String(AUTOGEN_STEP_ID)), + m_runAutogen(false) +{ + ctor(); +} + +AutogenStep::AutogenStep(ProjectExplorer::BuildStepList *bsl, const QString &id) : + AbstractProcessStep(bsl, id) +{ + ctor(); +} + +AutogenStep::AutogenStep(ProjectExplorer::BuildStepList *bsl, AutogenStep *bs) : + AbstractProcessStep(bsl, bs), + m_additionalArguments(bs->additionalArguments()) +{ + ctor(); +} + +void AutogenStep::ctor() +{ + setDefaultDisplayName(tr("Autogen")); +} + +AutogenStep::~AutogenStep() +{ +} + +AutotoolsBuildConfiguration *AutogenStep::autotoolsBuildConfiguration() const +{ + return static_cast<AutotoolsBuildConfiguration *>(buildConfiguration()); +} + +bool AutogenStep::init() +{ + AutotoolsBuildConfiguration *bc = autotoolsBuildConfiguration(); + + setEnabled(true); + + ProcessParameters *pp = processParameters(); + pp->setMacroExpander(bc->macroExpander()); + pp->setEnvironment(bc->environment()); + pp->setWorkingDirectory(bc->buildDirectory()); + pp->setCommand(QLatin1String("autogen.sh")); + pp->setArguments(additionalArguments()); + + return AbstractProcessStep::init(); +} + +void AutogenStep::run(QFutureInterface<bool> &interface) +{ + AutotoolsBuildConfiguration *bc = autotoolsBuildConfiguration(); + + // Check wether we need to run autogen.sh + const QFileInfo configureInfo(bc->buildDirectory() + QLatin1String("/configure")); + const QFileInfo configureAcInfo(bc->buildDirectory() + QLatin1String("/configure.ac")); + const QFileInfo makefileAmInfo(bc->buildDirectory() + QLatin1String("/Makefile.am")); + + if (!configureInfo.exists() + || configureInfo.lastModified() < configureAcInfo.lastModified() + || configureInfo.lastModified() < makefileAmInfo.lastModified()) { + m_runAutogen = true; + } + + if (!m_runAutogen) { + emit addOutput(tr("Configuration unchanged, skipping autogen step."), BuildStep::MessageOutput); + interface.reportResult(true); + return; + } + + m_runAutogen = false; + AbstractProcessStep::run(interface); +} + +ProjectExplorer::BuildStepConfigWidget* AutogenStep::createConfigWidget() +{ + return new AutogenStepConfigWidget(this); +} + +bool AutogenStep::immutable() const +{ + return false; +} + +void AutogenStep::setAdditionalArguments(const QString &list) +{ + if (list == m_additionalArguments) + return; + + m_additionalArguments = list; + m_runAutogen = true; + + emit additionalArgumentsChanged(list); +} + +QString AutogenStep::additionalArguments() const +{ + return m_additionalArguments; +} + +QVariantMap AutogenStep::toMap() const +{ + QVariantMap map(AbstractProcessStep::toMap()); + + map.insert(QLatin1String(AUTOGEN_ADDITIONAL_ARGUMENTS_KEY), m_additionalArguments); + return map; +} + +bool AutogenStep::fromMap(const QVariantMap &map) +{ + m_additionalArguments = map.value(QLatin1String(AUTOGEN_ADDITIONAL_ARGUMENTS_KEY)).toString(); + + return BuildStep::fromMap(map); +} + +////////////////////////////////// +// AutogenStepConfigWidget class +////////////////////////////////// +AutogenStepConfigWidget::AutogenStepConfigWidget(AutogenStep *autogenStep) : + m_autogenStep(autogenStep), + m_summaryText(), + m_additionalArguments(0) +{ + QFormLayout *fl = new QFormLayout(this); + fl->setMargin(0); + fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); + setLayout(fl); + + m_additionalArguments = new QLineEdit(this); + fl->addRow(tr("Arguments:"), m_additionalArguments); + m_additionalArguments->setText(m_autogenStep->additionalArguments()); + + updateDetails(); + + connect(m_additionalArguments, SIGNAL(textChanged(QString)), + autogenStep, SLOT(setAdditionalArguments(QString))); + connect(autogenStep, SIGNAL(additionalArgumentsChanged(QString)), + this, SLOT(updateDetails())); +} + +AutogenStepConfigWidget::~AutogenStepConfigWidget() +{ +} + +QString AutogenStepConfigWidget::displayName() const +{ + return tr("Autogen", "AutotoolsProjectManager::AutogenStepConfigWidget display name."); +} + +QString AutogenStepConfigWidget::summaryText() const +{ + return m_summaryText; +} + +void AutogenStepConfigWidget::updateDetails() +{ + AutotoolsBuildConfiguration *bc = m_autogenStep->autotoolsBuildConfiguration(); + + ProcessParameters param; + param.setMacroExpander(bc->macroExpander()); + param.setEnvironment(bc->environment()); + param.setWorkingDirectory(bc->buildDirectory()); + param.setCommand("autogen.sh"); + param.setArguments(m_autogenStep->additionalArguments()); + m_summaryText = param.summary(displayName()); + emit updateSummary(); +} diff --git a/src/plugins/autotoolsprojectmanager/autogenstep.h b/src/plugins/autotoolsprojectmanager/autogenstep.h new file mode 100644 index 00000000000..4fa05902115 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autogenstep.h @@ -0,0 +1,162 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef AUTOGENSTEP_H +#define AUTOGENSTEP_H + +#include <projectexplorer/abstractprocessstep.h> + +QT_BEGIN_NAMESPACE +class QLineEdit; +QT_END_NAMESPACE + +namespace AutotoolsProjectManager { +namespace Internal { + +class AutotoolsProject; +class AutotoolsBuildConfiguration; +class AutogenStep; +class AutogenStepConfigWidget; + +///////////////////////////// +// AutogenStepFactory class +///////////////////////////// +/** + * @brief Implementation of the ProjectExplorer::IBuildStepFactory interface. + * + * This factory is used to create instances of AutogenStep. + */ +class AutogenStepFactory : public ProjectExplorer::IBuildStepFactory +{ + Q_OBJECT + +public: + AutogenStepFactory(QObject *parent = 0); + ~AutogenStepFactory(); + + QStringList availableCreationIds(ProjectExplorer::BuildStepList *bc) const; + QString displayNameForId(const QString &id) const; + bool canCreate(ProjectExplorer::BuildStepList *parent, const QString &id) const; + ProjectExplorer::BuildStep *create(ProjectExplorer::BuildStepList *parent, const QString &id); + bool canClone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source) const; + ProjectExplorer::BuildStep *clone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source); + bool canRestore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map) const; + ProjectExplorer::BuildStep *restore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map); +}; + +/////////////////////// +// AutogenStep class +/////////////////////// +/** + * @brief Implementation of the ProjectExplorer::AbstractProcessStep interface. + * + * A autogen step can be configured by selecting the "Projects" button of Qt Creator + * (in the left hand side menu) and under "Build Settings". + * + * It is possible for the user to specify custom arguments. The corresponding + * configuration widget is created by AutogenStep::createConfigWidget and is + * represented by an instance of the class AutogenStepConfigWidget. + */ + +class AutogenStep : public ProjectExplorer::AbstractProcessStep +{ + Q_OBJECT + friend class AutogenStepFactory; + friend class AutogenStepConfigWidget; + +public: + AutogenStep(ProjectExplorer::BuildStepList *bsl); + ~AutogenStep(); + + AutotoolsBuildConfiguration *autotoolsBuildConfiguration() const; + bool init(); + void run(QFutureInterface<bool> &interface); + ProjectExplorer::BuildStepConfigWidget *createConfigWidget(); + bool immutable() const; + QString additionalArguments() const; + QVariantMap toMap() const; + +public slots: + void setAdditionalArguments(const QString &list); + +signals: + void additionalArgumentsChanged(const QString &); + +protected: + AutogenStep(ProjectExplorer::BuildStepList *bsl, AutogenStep *bs); + AutogenStep(ProjectExplorer::BuildStepList *bsl, const QString &id); + + bool fromMap(const QVariantMap &map); + +private: + void ctor(); + + QString m_additionalArguments; + bool m_runAutogen; +}; + +////////////////////////////////// +// AutogenStepConfigWidget class +////////////////////////////////// +/** + * @brief Implementation of the ProjectExplorer::BuildStepConfigWidget interface. + * + * Allows to configure a autogen step in the GUI. + */ +class AutogenStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget +{ + Q_OBJECT + +public: + AutogenStepConfigWidget(AutogenStep *autogenStep); + ~AutogenStepConfigWidget(); + + QString displayName() const; + QString summaryText() const; + + +private slots: + void updateDetails(); + +private: + AutogenStep *m_autogenStep; + QString m_summaryText; + QLineEdit *m_additionalArguments; +}; + +} // namespace Internal +} // namespace AutotoolsProjectManager + +#endif // AUTOGENSTEP_H + diff --git a/src/plugins/autotoolsprojectmanager/autoreconfstep.cpp b/src/plugins/autotoolsprojectmanager/autoreconfstep.cpp new file mode 100644 index 00000000000..2769ec50e50 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autoreconfstep.cpp @@ -0,0 +1,299 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "autoreconfstep.h" +#include "autotoolsproject.h" +#include "autotoolstarget.h" +#include "autotoolsbuildconfiguration.h" +#include "autotoolsprojectconstants.h" + +#include <projectexplorer/buildsteplist.h> +#include <projectexplorer/toolchain.h> +#include <projectexplorer/gnumakeparser.h> +#include <projectexplorer/projectexplorer.h> +#include <projectexplorer/projectexplorerconstants.h> +#include <utils/qtcprocess.h> + +#include <QtCore/QVariantMap> +#include <QtGui/QLineEdit> +#include <QtGui/QFormLayout> + +using namespace AutotoolsProjectManager; +using namespace AutotoolsProjectManager::Internal; +using namespace ProjectExplorer; + +namespace { +const char AUTORECONF_STEP_ID[] = "AutotoolsProjectManager.AutoreconfStep"; +const char AUTORECONF_ADDITIONAL_ARGUMENTS_KEY[] = "AutotoolsProjectManager.AutoreconfStep.AdditionalArguments"; +} + +//////////////////////////////// +// AutoreconfStepFactory class +//////////////////////////////// +AutoreconfStepFactory::AutoreconfStepFactory(QObject *parent) : + ProjectExplorer::IBuildStepFactory(parent) +{ +} + +AutoreconfStepFactory::~AutoreconfStepFactory() +{ +} + +QStringList AutoreconfStepFactory::availableCreationIds(BuildStepList *parent) const +{ + if (parent->target()->project()->id() == QLatin1String(Constants::AUTOTOOLS_PROJECT_ID)) + return QStringList() << QLatin1String(AUTORECONF_STEP_ID); + return QStringList(); +} + +QString AutoreconfStepFactory::displayNameForId(const QString &id) const +{ + if (id == QLatin1String(AUTORECONF_STEP_ID)) + return tr("Autoreconf", "Display name for AutotoolsProjectManager::AutoreconfStep id."); + return QString(); +} + +bool AutoreconfStepFactory::canCreate(BuildStepList *parent, const QString &id) const +{ + if (parent->target()->project()->id() != QLatin1String(Constants::AUTOTOOLS_PROJECT_ID)) + return false; + + if (parent->id() != ProjectExplorer::Constants::BUILDSTEPS_BUILD) + return false; + + return QLatin1String(AUTORECONF_STEP_ID) == id; +} + +BuildStep *AutoreconfStepFactory::create(BuildStepList *parent, const QString &id) +{ + if (!canCreate(parent, id)) + return 0; + return new AutoreconfStep(parent); +} + +bool AutoreconfStepFactory::canClone(BuildStepList *parent, BuildStep *source) const +{ + return canCreate(parent, source->id()); +} + +BuildStep *AutoreconfStepFactory::clone(BuildStepList *parent, BuildStep *source) +{ + if (!canClone(parent, source)) + return 0; + return new AutoreconfStep(parent, static_cast<AutoreconfStep *>(source)); +} + +bool AutoreconfStepFactory::canRestore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map) const +{ + QString id(ProjectExplorer::idFromMap(map)); + return canCreate(parent, id); +} + +BuildStep *AutoreconfStepFactory::restore(BuildStepList *parent, const QVariantMap &map) +{ + if (!canRestore(parent, map)) + return 0; + AutoreconfStep *bs = new AutoreconfStep(parent); + if (bs->fromMap(map)) + return bs; + delete bs; + return 0; +} + +///////////////////////// +// AutoreconfStep class +///////////////////////// +AutoreconfStep::AutoreconfStep(ProjectExplorer::BuildStepList *bsl) : + AbstractProcessStep(bsl, QLatin1String(AUTORECONF_STEP_ID)), + m_runAutoreconf(false) +{ + ctor(); +} + +AutoreconfStep::AutoreconfStep(ProjectExplorer::BuildStepList *bsl, const QString &id) : + AbstractProcessStep(bsl, id) +{ + ctor(); +} + +AutoreconfStep::AutoreconfStep(ProjectExplorer::BuildStepList *bsl, AutoreconfStep *bs) : + AbstractProcessStep(bsl, bs), + m_additionalArguments(bs->additionalArguments()) +{ + ctor(); +} + +void AutoreconfStep::ctor() +{ + setDefaultDisplayName(tr("Autoreconf")); +} + +AutoreconfStep::~AutoreconfStep() +{ +} + +AutotoolsBuildConfiguration *AutoreconfStep::autotoolsBuildConfiguration() const +{ + return static_cast<AutotoolsBuildConfiguration *>(buildConfiguration()); +} + +bool AutoreconfStep::init() +{ + AutotoolsBuildConfiguration *bc = autotoolsBuildConfiguration(); + + setEnabled(true); + + ProcessParameters *pp = processParameters(); + pp->setMacroExpander(bc->macroExpander()); + pp->setEnvironment(bc->environment()); + pp->setWorkingDirectory(bc->buildDirectory()); + pp->setCommand("autoreconf"); + pp->setArguments(additionalArguments()); + + return AbstractProcessStep::init(); +} + +void AutoreconfStep::run(QFutureInterface<bool> &interface) +{ + AutotoolsBuildConfiguration *bc = autotoolsBuildConfiguration(); + + // Check wether we need to run autoreconf + const QFileInfo configureInfo(bc->buildDirectory() + QLatin1String("/configure")); + + if (!configureInfo.exists()) + m_runAutoreconf = true; + + if (!m_runAutoreconf) { + emit addOutput(tr("Configuration unchanged, skipping autoreconf step."), BuildStep::MessageOutput); + interface.reportResult(true); + return; + } + + m_runAutoreconf = false; + AbstractProcessStep::run(interface); +} + +ProjectExplorer::BuildStepConfigWidget* AutoreconfStep::createConfigWidget() +{ + return new AutoreconfStepConfigWidget(this); +} + +bool AutoreconfStep::immutable() const +{ + return false; +} + +void AutoreconfStep::setAdditionalArguments(const QString &list) +{ + if (list == m_additionalArguments) + return; + + m_additionalArguments = list; + m_runAutoreconf = true; + + emit additionalArgumentsChanged(list); +} + +QString AutoreconfStep::additionalArguments() const +{ + return m_additionalArguments; +} + +QVariantMap AutoreconfStep::toMap() const +{ + QVariantMap map(AbstractProcessStep::toMap()); + + map.insert(QLatin1String(AUTORECONF_ADDITIONAL_ARGUMENTS_KEY), m_additionalArguments); + return map; +} + +bool AutoreconfStep::fromMap(const QVariantMap &map) +{ + m_additionalArguments = map.value(QLatin1String(AUTORECONF_ADDITIONAL_ARGUMENTS_KEY)).toString(); + + return BuildStep::fromMap(map); +} + +////////////////////////////////////// +// AutoreconfStepConfigWidget class +////////////////////////////////////// +AutoreconfStepConfigWidget::AutoreconfStepConfigWidget(AutoreconfStep *autoreconfStep) : + m_autoreconfStep(autoreconfStep), + m_summaryText(), + m_additionalArguments(0) +{ + QFormLayout *fl = new QFormLayout(this); + fl->setMargin(0); + fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); + setLayout(fl); + + m_additionalArguments = new QLineEdit(this); + fl->addRow(tr("Arguments:"), m_additionalArguments); + m_additionalArguments->setText(m_autoreconfStep->additionalArguments()); + + updateDetails(); + + connect(m_additionalArguments, SIGNAL(textChanged(QString)), + autoreconfStep, SLOT(setAdditionalArguments(QString))); + connect(autoreconfStep, SIGNAL(additionalArgumentsChanged(QString)), + this, SLOT(updateDetails())); +} + +AutoreconfStepConfigWidget::~AutoreconfStepConfigWidget() +{ +} + +QString AutoreconfStepConfigWidget::displayName() const +{ + return tr("Autoreconf", "AutotoolsProjectManager::AutoreconfStepConfigWidget display name."); +} + +QString AutoreconfStepConfigWidget::summaryText() const +{ + return m_summaryText; +} + +void AutoreconfStepConfigWidget::updateDetails() +{ + AutotoolsBuildConfiguration *bc = m_autoreconfStep->autotoolsBuildConfiguration(); + + ProcessParameters param; + param.setMacroExpander(bc->macroExpander()); + param.setEnvironment(bc->environment()); + param.setWorkingDirectory(bc->buildDirectory()); + param.setCommand("autoreconf"); + param.setArguments(m_autoreconfStep->additionalArguments()); + m_summaryText = param.summary(displayName()); + emit updateSummary(); +} diff --git a/src/plugins/autotoolsprojectmanager/autoreconfstep.h b/src/plugins/autotoolsprojectmanager/autoreconfstep.h new file mode 100644 index 00000000000..bafe0df6a03 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autoreconfstep.h @@ -0,0 +1,163 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef AUTORECONFSTEP_H +#define AUTORECONFSTEP_H + +#include <projectexplorer/abstractprocessstep.h> +#include <QtGui/QLineEdit> + +QT_BEGIN_NAMESPACE +class QLineEdit; +QT_END_NAMESPACE + +namespace AutotoolsProjectManager { +namespace Internal { + +class AutotoolsProject; +class AutotoolsBuildConfiguration; +class AutoreconfStep; + +//////////////////////////////// +// AutoreconfStepFactory class +//////////////////////////////// +/** + * @brief Implementation of the ProjectExplorer::IBuildStepFactory interface. + * + * The factory is used to create instances of AutoreconfStep. + */ +class AutoreconfStepFactory : public ProjectExplorer::IBuildStepFactory +{ + Q_OBJECT + +public: + AutoreconfStepFactory(QObject *parent = 0); + ~AutoreconfStepFactory(); + + QStringList availableCreationIds(ProjectExplorer::BuildStepList *bc) const; + QString displayNameForId(const QString &id) const; + + bool canCreate(ProjectExplorer::BuildStepList *parent, const QString &id) const; + ProjectExplorer::BuildStep *create(ProjectExplorer::BuildStepList *parent, const QString &id); + bool canClone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source) const; + ProjectExplorer::BuildStep *clone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source); + bool canRestore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map) const; + ProjectExplorer::BuildStep *restore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map); +}; + +///////////////////////// +// AutoreconfStep class +///////////////////////// +/** + * @brief Implementation of the ProjectExplorer::AbstractProcessStep interface. + * + * A autoreconf step can be configured by selecting the "Projects" button + * of Qt Creator (in the left hand side menu) and under "Build Settings". + * + * It is possible for the user to specify custom arguments. The corresponding + * configuration widget is created by AutoreconfStep::createConfigWidget and is + * represented by an instance of the class AutoreconfStepConfigWidget. + */ + +class AutoreconfStep : public ProjectExplorer::AbstractProcessStep +{ + Q_OBJECT + friend class AutoreconfStepFactory; + friend class AutoreconfStepConfigWidget; + +public: + + AutoreconfStep(ProjectExplorer::BuildStepList *bsl); + ~AutoreconfStep(); + + AutotoolsBuildConfiguration *autotoolsBuildConfiguration() const; + bool init(); + void run(QFutureInterface<bool> &interface); + ProjectExplorer::BuildStepConfigWidget *createConfigWidget(); + bool immutable() const; + QString additionalArguments() const; + QVariantMap toMap() const; + +public slots: + void setAdditionalArguments(const QString &list); + +signals: + void additionalArgumentsChanged(const QString &); + +protected: + AutoreconfStep(ProjectExplorer::BuildStepList *bsl, AutoreconfStep *bs); + AutoreconfStep(ProjectExplorer::BuildStepList *bsl, const QString &id); + + bool fromMap(const QVariantMap &map); + +private: + void ctor(); + + QString m_additionalArguments; + bool m_runAutoreconf; +}; + +////////////////////////////////////// +// AutoreconfStepConfigWidget class +////////////////////////////////////// +/** + * @brief Implementation of the ProjectExplorer::BuildStepConfigWidget interface. + * + * Allows to configure a autoreconf step in the GUI.. + */ +class AutoreconfStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget +{ + Q_OBJECT + +public: + AutoreconfStepConfigWidget(AutoreconfStep *autoreconfStep); + ~AutoreconfStepConfigWidget(); + + QString displayName() const; + QString summaryText() const; + +private slots: + void updateDetails(); + +private: + AutoreconfStep *m_autoreconfStep; + QString m_summaryText; + QLineEdit *m_additionalArguments; +}; + +} // namespace Internal +} // namespace AutotoolsProjectManager + +#endif // AUTORECONFSTEP_H + diff --git a/src/plugins/autotoolsprojectmanager/autotoolsbuildconfiguration.cpp b/src/plugins/autotoolsprojectmanager/autotoolsbuildconfiguration.cpp new file mode 100644 index 00000000000..80f7ba3ab04 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsbuildconfiguration.cpp @@ -0,0 +1,260 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "autotoolsbuildconfiguration.h" +#include "makestep.h" +#include "autotoolsproject.h" +#include "autotoolstarget.h" +#include "autotoolsprojectconstants.h" +#include "makestep.h" +#include "autogenstep.h" +#include "autoreconfstep.h" +#include "configurestep.h" + +#include <projectexplorer/buildsteplist.h> +#include <projectexplorer/toolchain.h> +#include <projectexplorer/projectexplorerconstants.h> +#include <projectexplorer/customexecutablerunconfiguration.h> +#include <utils/qtcassert.h> + +#include <QtGui/QInputDialog> + +using namespace AutotoolsProjectManager; +using namespace Internal; + +////////////////////////////////////// +// AutotoolsBuildConfiguration class +////////////////////////////////////// +AutotoolsBuildConfiguration::AutotoolsBuildConfiguration(AutotoolsTarget *parent) + : BuildConfiguration(parent, QLatin1String(Constants::AUTOTOOLS_BC_ID)) +{ + m_buildDirectory = autotoolsTarget()->defaultBuildDirectory(); +} + +AutotoolsBuildConfiguration::AutotoolsBuildConfiguration(AutotoolsTarget *parent, const QString &id) + : BuildConfiguration(parent, id) +{ +} + +AutotoolsBuildConfiguration::AutotoolsBuildConfiguration(AutotoolsTarget *parent, AutotoolsBuildConfiguration *source) + : BuildConfiguration(parent, source), + m_buildDirectory(source->m_buildDirectory) +{ + cloneSteps(source); +} + +AutotoolsBuildConfiguration::~AutotoolsBuildConfiguration() +{ +} + +QVariantMap AutotoolsBuildConfiguration::toMap() const +{ + QVariantMap map(ProjectExplorer::BuildConfiguration::toMap()); + map.insert(QLatin1String(Constants::BUILD_DIRECTORY_KEY), m_buildDirectory); + return map; +} + +bool AutotoolsBuildConfiguration::fromMap(const QVariantMap &map) +{ + if (!BuildConfiguration::fromMap(map)) + return false; + + m_buildDirectory = map.value(QLatin1String(Constants::BUILD_DIRECTORY_KEY), autotoolsTarget()->defaultBuildDirectory()).toString(); + return true; +} + +QString AutotoolsBuildConfiguration::buildDirectory() const +{ + return m_buildDirectory; +} + +void AutotoolsBuildConfiguration::setBuildDirectory(const QString &buildDirectory) +{ + if (m_buildDirectory == buildDirectory) + return; + m_buildDirectory = buildDirectory; + emit buildDirectoryChanged(); +} + +AutotoolsTarget *AutotoolsBuildConfiguration::autotoolsTarget() const +{ + return static_cast<AutotoolsTarget *>(target()); +} + +ProjectExplorer::IOutputParser *AutotoolsBuildConfiguration::createOutputParser() const +{ + ProjectExplorer::ToolChain *tc = autotoolsTarget()->autotoolsProject()->toolChain(); + if (tc) + return tc->outputParser(); + return 0; +} + +////////////////////////////////////// +// AutotoolsBuildConfiguration class +////////////////////////////////////// +AutotoolsBuildConfigurationFactory::AutotoolsBuildConfigurationFactory(QObject *parent) : + ProjectExplorer::IBuildConfigurationFactory(parent) +{ +} + +AutotoolsBuildConfigurationFactory::~AutotoolsBuildConfigurationFactory() +{ +} + +QStringList AutotoolsBuildConfigurationFactory::availableCreationIds(ProjectExplorer::Target *parent) const +{ + if (!qobject_cast<AutotoolsTarget *>(parent)) + return QStringList(); + return QStringList() << QLatin1String(Constants::AUTOTOOLS_BC_ID); +} + +QString AutotoolsBuildConfigurationFactory::displayNameForId(const QString &id) const +{ + if (id == QLatin1String(Constants::AUTOTOOLS_BC_ID)) + return tr("Build"); + return QString(); +} + +bool AutotoolsBuildConfigurationFactory::canCreate(ProjectExplorer::Target *parent, const QString &id) const +{ + if (!qobject_cast<AutotoolsTarget *>(parent)) + return false; + if (id == QLatin1String(Constants::AUTOTOOLS_BC_ID)) + return true; + return false; +} + +AutotoolsBuildConfiguration *AutotoolsBuildConfigurationFactory::create(ProjectExplorer::Target *parent, const QString &id) +{ + if (!canCreate(parent, id)) + return 0; + + AutotoolsTarget *t(static_cast<AutotoolsTarget *>(parent)); + AutotoolsBuildConfiguration *bc =createDefaultConfiguration(t); + + bool ok; + QString buildConfigurationName = QInputDialog::getText(0, + tr("New Configuration"), + tr("New configuration name:"), + QLineEdit::Normal, + QString(), + &ok); + + if (!ok || buildConfigurationName.isEmpty()) + return 0; + bc->setDisplayName(buildConfigurationName); + + t->addBuildConfiguration(bc); + t->addDeployConfiguration(t->createDeployConfiguration(ProjectExplorer::Constants::DEFAULT_DEPLOYCONFIGURATION_ID)); + // User needs to choose where the executable file is. + // TODO: Parse the file in *Anjuta style* to be able to add custom RunConfigurations. + t->addRunConfiguration(new ProjectExplorer::CustomExecutableRunConfiguration(t)); + + return bc; +} + +AutotoolsBuildConfiguration *AutotoolsBuildConfigurationFactory::createDefaultConfiguration(AutotoolsTarget *target) const +{ + AutotoolsBuildConfiguration *bc = new AutotoolsBuildConfiguration(target); + ProjectExplorer::BuildStepList *buildSteps = bc->stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); + + // ### Build Steps Build ### + // autogen.sh or autoreconf + QFile autogenFile(target->autotoolsProject()->sourceDirectory() + QLatin1String("/autogen.sh")); + if (autogenFile.exists()) { + AutogenStep *autogenStep = new AutogenStep(buildSteps); + buildSteps->insertStep(0, autogenStep); + } else { + AutoreconfStep *autoreconfStep = new AutoreconfStep(buildSteps); + autoreconfStep->setAdditionalArguments(QLatin1String("--force --install")); + buildSteps->insertStep(0, autoreconfStep); + } + + // ./configure. + ConfigureStep *configureStep = new ConfigureStep(buildSteps); + buildSteps->insertStep(1, configureStep); + + // make + MakeStep *makeStep = new MakeStep(buildSteps); + buildSteps->insertStep(2, makeStep); + makeStep->setBuildTarget(QLatin1String("all"), /*on =*/ true); + + // ### Build Steps Clean ### + ProjectExplorer::BuildStepList *cleanSteps = bc->stepList(ProjectExplorer::Constants::BUILDSTEPS_CLEAN); + MakeStep *cleanMakeStep = new MakeStep(cleanSteps); + cleanMakeStep->setAdditionalArguments(QLatin1String("clean")); + cleanMakeStep->setClean(true); + cleanSteps->insertStep(0, cleanMakeStep); + + return bc; +} + +bool AutotoolsBuildConfigurationFactory::canClone(ProjectExplorer::Target *parent, ProjectExplorer::BuildConfiguration *source) const +{ + return canCreate(parent, source->id()); +} + +AutotoolsBuildConfiguration *AutotoolsBuildConfigurationFactory::clone(ProjectExplorer::Target *parent, ProjectExplorer::BuildConfiguration *source) +{ + if (!canClone(parent, source)) + return 0; + + AutotoolsBuildConfiguration *origin = static_cast<AutotoolsBuildConfiguration *>(source); + AutotoolsTarget *target(static_cast<AutotoolsTarget *>(parent)); + return new AutotoolsBuildConfiguration(target, origin); +} + +bool AutotoolsBuildConfigurationFactory::canRestore(ProjectExplorer::Target *parent, const QVariantMap &map) const +{ + QString id(ProjectExplorer::idFromMap(map)); + return canCreate(parent, id); +} + +AutotoolsBuildConfiguration *AutotoolsBuildConfigurationFactory::restore(ProjectExplorer::Target *parent, const QVariantMap &map) +{ + if (!canRestore(parent, map)) + return 0; + AutotoolsTarget *target(static_cast<AutotoolsTarget *>(parent)); + AutotoolsBuildConfiguration *bc = new AutotoolsBuildConfiguration(target); + if (bc->fromMap(map)) + return bc; + delete bc; + return 0; +} + +ProjectExplorer::BuildConfiguration::BuildType AutotoolsBuildConfiguration::buildType() const +{ + // TODO: Should I return something different from Unknown? + return Unknown; +} diff --git a/src/plugins/autotoolsprojectmanager/autotoolsbuildconfiguration.h b/src/plugins/autotoolsprojectmanager/autotoolsbuildconfiguration.h new file mode 100644 index 00000000000..9889a1c6772 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsbuildconfiguration.h @@ -0,0 +1,94 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef AUTOTOOLSBUILDCONFIGURATION_H +#define AUTOTOOLSBUILDCONFIGURATION_H + +#include <projectexplorer/buildconfiguration.h> + +namespace AutotoolsProjectManager { +namespace Internal { + +class AutotoolsTarget; +class AutotoolsBuildConfigurationFactory; + +class AutotoolsBuildConfiguration : public ProjectExplorer::BuildConfiguration +{ + Q_OBJECT + friend class AutotoolsBuildConfigurationFactory; + +public: + explicit AutotoolsBuildConfiguration(AutotoolsTarget *parent); + ~AutotoolsBuildConfiguration(); + + AutotoolsTarget *autotoolsTarget() const; + QString buildDirectory() const; + void setBuildDirectory(const QString &buildDirectory); + QVariantMap toMap() const; + ProjectExplorer::IOutputParser *createOutputParser() const; + BuildType buildType() const; + +protected: + AutotoolsBuildConfiguration(AutotoolsTarget *parent, const QString &id); + AutotoolsBuildConfiguration(AutotoolsTarget *parent, AutotoolsBuildConfiguration *source); + + bool fromMap(const QVariantMap &map); + +private: + QString m_buildDirectory; +}; + +class AutotoolsBuildConfigurationFactory : public ProjectExplorer::IBuildConfigurationFactory +{ + Q_OBJECT + +public: + explicit AutotoolsBuildConfigurationFactory(QObject *parent = 0); + ~AutotoolsBuildConfigurationFactory(); + + QStringList availableCreationIds(ProjectExplorer::Target *parent) const; + QString displayNameForId(const QString &id) const; + + bool canCreate(ProjectExplorer::Target *parent, const QString &id) const; + AutotoolsBuildConfiguration *create(ProjectExplorer::Target *parent, const QString &id); + AutotoolsBuildConfiguration *createDefaultConfiguration(AutotoolsTarget *target) const; + bool canClone(ProjectExplorer::Target *parent, ProjectExplorer::BuildConfiguration *source) const; + AutotoolsBuildConfiguration *clone(ProjectExplorer::Target *parent, ProjectExplorer::BuildConfiguration *source); + bool canRestore(ProjectExplorer::Target *parent, const QVariantMap &map) const; + AutotoolsBuildConfiguration *restore(ProjectExplorer::Target *parent, const QVariantMap &map); +}; + +} // namespace Internal +} // namespace AutotoolsProjectManager +#endif // AUTOTOOLSBUILDCONFIGURATION_H diff --git a/src/plugins/autotoolsprojectmanager/autotoolsbuildsettingswidget.cpp b/src/plugins/autotoolsprojectmanager/autotoolsbuildsettingswidget.cpp new file mode 100644 index 00000000000..7d05b051e63 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsbuildsettingswidget.cpp @@ -0,0 +1,139 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "autotoolsbuildsettingswidget.h" +#include "autotoolsproject.h" +#include "autotoolsbuildconfiguration.h" + +#include <projectexplorer/projectexplorer.h> +#include <projectexplorer/toolchainmanager.h> + +#include <QtGui/QGridLayout> +#include <QtGui/QLabel> +#include <QtGui/QLineEdit> +#include <QtGui/QFormLayout> +#include <QtGui/QComboBox> +#include <QtCore/QPointer> + +using namespace AutotoolsProjectManager; +using namespace AutotoolsProjectManager::Internal; +using namespace ProjectExplorer; + +AutotoolsBuildSettingsWidget::AutotoolsBuildSettingsWidget(AutotoolsTarget *target) : + m_target(target), + m_pathChooser(0), + m_toolChainChooser(0), + m_buildConfiguration(0) +{ + QFormLayout *fl = new QFormLayout(this); + fl->setContentsMargins(0, 0, 0, 0); + fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); + + m_pathChooser = new Utils::PathChooser(this); + m_pathChooser->setEnabled(true); + m_pathChooser->setExpectedKind(Utils::PathChooser::Directory); + m_pathChooser->setBaseDirectory(m_target->autotoolsProject()->projectDirectory()); + fl->addRow(tr("Build directory:"), m_pathChooser); + connect(m_pathChooser, SIGNAL(changed(QString)), this, SLOT(buildDirectoryChanged())); + + // tool chain + m_toolChainChooser = new QComboBox; + m_toolChainChooser->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + updateToolChainList(); + + fl->addRow(tr("Tool chain:"), m_toolChainChooser); + connect(m_toolChainChooser, SIGNAL(activated(int)), this, SLOT(toolChainSelected(int))); + connect(m_target->autotoolsProject(), SIGNAL(toolChainChanged(ProjectExplorer::ToolChain*)), + this, SLOT(toolChainChanged(ProjectExplorer::ToolChain*))); + connect(ProjectExplorer::ToolChainManager::instance(), SIGNAL(toolChainAdded(ProjectExplorer::ToolChain*)), + this, SLOT(updateToolChainList())); + connect(ProjectExplorer::ToolChainManager::instance(), SIGNAL(toolChainRemoved(ProjectExplorer::ToolChain*)), + this, SLOT(updateToolChainList())); +} + +AutotoolsBuildSettingsWidget::~AutotoolsBuildSettingsWidget() +{ +} + +QString AutotoolsBuildSettingsWidget::displayName() const +{ + return QLatin1String("Autotools Manager"); +} + +void AutotoolsBuildSettingsWidget::init(BuildConfiguration *bc) +{ + m_buildConfiguration = static_cast<AutotoolsBuildConfiguration *>(bc); + m_pathChooser->setPath(m_buildConfiguration->buildDirectory()); +} + +void AutotoolsBuildSettingsWidget::buildDirectoryChanged() +{ + m_buildConfiguration->setBuildDirectory(m_pathChooser->rawPath()); +} + +void AutotoolsBuildSettingsWidget::toolChainSelected(int index) +{ + using namespace ProjectExplorer; + + ToolChain *tc = static_cast<ToolChain *>(m_toolChainChooser->itemData(index).value<void *>()); + m_target->autotoolsProject()->setToolChain(tc); +} + +void AutotoolsBuildSettingsWidget::toolChainChanged(ProjectExplorer::ToolChain *tc) +{ + for (int i = 0; i < m_toolChainChooser->count(); ++i) { + ToolChain * currentTc = static_cast<ToolChain *>(m_toolChainChooser->itemData(i).value<void *>()); + if (currentTc != tc) + continue; + m_toolChainChooser->setCurrentIndex(i); + return; + } +} + +void AutotoolsBuildSettingsWidget::updateToolChainList() +{ + m_toolChainChooser->clear(); + + QList<ToolChain *> tcs = ToolChainManager::instance()->toolChains(); + if (!m_target->autotoolsProject()->toolChain()) { + m_toolChainChooser->addItem(tr("<Invalid tool chain>"), qVariantFromValue(static_cast<void *>(0))); + m_toolChainChooser->setCurrentIndex(0); + } + foreach (ToolChain *tc, tcs) { + m_toolChainChooser->addItem(tc->displayName(), qVariantFromValue(static_cast<void *>(tc))); + if (m_target->autotoolsProject()->toolChain() + && m_target->autotoolsProject()->toolChain()->id() == tc->id()) + m_toolChainChooser->setCurrentIndex(m_toolChainChooser->count() - 1); + } +} diff --git a/src/plugins/autotoolsprojectmanager/autotoolsbuildsettingswidget.h b/src/plugins/autotoolsprojectmanager/autotoolsbuildsettingswidget.h new file mode 100644 index 00000000000..6fc3be08ade --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsbuildsettingswidget.h @@ -0,0 +1,88 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef AUTOTOOLSBUILDSETTINGSWIDGET_H +#define AUTOTOOLSBUILDSETTINGSWIDGET_H + +#include "autotoolstarget.h" +#include "autotoolsbuildconfiguration.h" + +#include <projectexplorer/buildconfiguration.h> +#include <projectexplorer/project.h> +#include <projectexplorer/toolchain.h> +#include <projectexplorer/buildstep.h> +#include <utils/pathchooser.h> + +QT_BEGIN_NAMESPACE +class QComboBox; +QT_END_NAMESPACE + +namespace AutotoolsProjectManager { +namespace Internal { + +class AutotoolsProject; + +/** + * @brief Implementation of ProjectExplorer::BuildConfigWidget interface. + * + * Provides an editor to configure the build directory and build steps. + */ +class AutotoolsBuildSettingsWidget : public ProjectExplorer::BuildConfigWidget +{ + Q_OBJECT + +public: + AutotoolsBuildSettingsWidget(AutotoolsTarget* target); + ~AutotoolsBuildSettingsWidget(); + + QString displayName() const; + void init(ProjectExplorer::BuildConfiguration* bc); + +private slots: + void buildDirectoryChanged(); + void toolChainSelected(int index); + void toolChainChanged(ProjectExplorer::ToolChain *); + void updateToolChainList(); + +private: + AutotoolsTarget *m_target; + Utils::PathChooser *m_pathChooser; + QComboBox *m_toolChainChooser; + AutotoolsBuildConfiguration *m_buildConfiguration; +}; + +} // namespace Internal +} // namespace AutotoolsProjectManager + +#endif // AUTOTOOLSBUILDSETTINGSWIDGET_H diff --git a/src/plugins/autotoolsprojectmanager/autotoolsmanager.cpp b/src/plugins/autotoolsprojectmanager/autotoolsmanager.cpp new file mode 100644 index 00000000000..474fb6997e3 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsmanager.cpp @@ -0,0 +1,83 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "autotoolsmanager.h" +#include "autotoolsproject.h" +#include "autotoolsprojectconstants.h" + +#include <coreplugin/icore.h> +#include <coreplugin/ifile.h> +#include <coreplugin/messagemanager.h> +#include <projectexplorer/projectexplorerconstants.h> +#include <projectexplorer/projectexplorer.h> +#include <projectexplorer/session.h> + +using namespace AutotoolsProjectManager::Internal; + +AutotoolsManager::AutotoolsManager() +{ +} + +AutotoolsManager::~AutotoolsManager() +{ +} + +ProjectExplorer::Project *AutotoolsManager::openProject(const QString& fileName, QString *errorString) +{ + QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath(); + + if (canonicalFilePath.isEmpty()) { + if (errorString) + *errorString = tr("Failed opening project '%1': Project file does not exist") + .arg(QDir::toNativeSeparators(fileName)); + return 0; + } + + // Check whether the project is already open or not. + ProjectExplorer::ProjectExplorerPlugin *projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance(); + foreach (ProjectExplorer::Project *pi, projectExplorer->session()->projects()) { + if (canonicalFilePath == pi->file()->fileName()) { + *errorString = tr("Failed opening project '%1': Project already open") + .arg(QDir::toNativeSeparators(canonicalFilePath)); + return 0; + } + } + + return new AutotoolsProject(this, canonicalFilePath); +} + +QString AutotoolsManager::mimeType() const +{ + return QLatin1String(Constants::MAKEFILE_MIMETYPE); +} diff --git a/src/plugins/autotoolsprojectmanager/autotoolsmanager.h b/src/plugins/autotoolsprojectmanager/autotoolsmanager.h new file mode 100644 index 00000000000..2f9aaa6d1ef --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsmanager.h @@ -0,0 +1,65 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef AUTOTOOLSMANAGER_H +#define AUTOTOOLSMANAGER_H + +#include <projectexplorer/iprojectmanager.h> + +namespace AutotoolsProjectManager { +namespace Internal { + +/** + * @brief Implementation of ProjectExplorer::IProjectManager interface. + * + * An autotools project is identified by the MIME type text/x-makefile. + * The project is represented by an instance of ProjectExplorer::Project, + * which gets created by AutotoolsManager::openProject(). + */ +class AutotoolsManager : public ProjectExplorer::IProjectManager +{ + Q_OBJECT + +public: + AutotoolsManager(); + ~AutotoolsManager(); + + ProjectExplorer::Project *openProject(const QString& fileName, QString *errorString); + QString mimeType() const; +}; + +} // namespace Internal +} // namespace AutotoolsProjectManager + +#endif // AUTOTOOLSMANAGER_H diff --git a/src/plugins/autotoolsprojectmanager/autotoolsopenprojectwizard.cpp b/src/plugins/autotoolsprojectmanager/autotoolsopenprojectwizard.cpp new file mode 100644 index 00000000000..d53a42acc97 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsopenprojectwizard.cpp @@ -0,0 +1,121 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "autotoolsopenprojectwizard.h" + +#include <QtGui/QVBoxLayout> +#include <QtGui/QFormLayout> +#include <QtGui/QLabel> +#include <QtCore/QDir> + +using namespace AutotoolsProjectManager; +using namespace AutotoolsProjectManager::Internal; + +////////////////////////////////////// +// AutotoolsOpenProjectWizard class +////////////////////////////////////// +AutotoolsOpenProjectWizard::AutotoolsOpenProjectWizard(AutotoolsManager *manager, + const QString &sourceDirectory, + QWidget *parent) + : Utils::Wizard(parent), + m_manager(manager), + m_sourceDirectory(sourceDirectory) +{ + QDir dir(m_sourceDirectory); + m_buildDirectory = dir.absolutePath(); + + setPage(BuildPathPageId, new BuildPathPage(this)); + + setStartId(BuildPathPageId); + init(); +} + +AutotoolsOpenProjectWizard::~AutotoolsOpenProjectWizard() +{ +} + +void AutotoolsOpenProjectWizard::init() +{ + setOption(QWizard::NoBackButtonOnStartPage); + setWindowTitle(tr("Autotools Wizard")); +} + +AutotoolsManager *AutotoolsOpenProjectWizard::autotoolsManager() const +{ + return m_manager; +} + +QString AutotoolsOpenProjectWizard::buildDirectory() const +{ + return m_buildDirectory; +} + +QString AutotoolsOpenProjectWizard::sourceDirectory() const +{ + return m_sourceDirectory; +} + +void AutotoolsOpenProjectWizard::setBuildDirectory(const QString &directory) +{ + m_buildDirectory = directory; +} + +///////////////////////// +// BuildPathPage class +///////////////////////// +BuildPathPage::BuildPathPage(AutotoolsOpenProjectWizard *wizard) + : QWizardPage(wizard), m_wizard(wizard) +{ + QFormLayout *fl = new QFormLayout; + this->setLayout(fl); + + QLabel *label = new QLabel(this); + label->setWordWrap(true); + label->setText(tr("Please enter the directory in which you want to build your project. " + "Qt Creator recommends to not use the source directory for building. " + "This ensures that the source directory remains clean and enables multiple builds " + "with different settings.")); + fl->addWidget(label); + m_pc = new Utils::PathChooser(this); + m_pc->setBaseDirectory(m_wizard->sourceDirectory()); + m_pc->setPath(m_wizard->buildDirectory()); + connect(m_pc, SIGNAL(changed(QString)), this, SLOT(buildDirectoryChanged())); + fl->addRow(tr("Build directory:"), m_pc); + setTitle(tr("Build Location")); +} + +void BuildPathPage::buildDirectoryChanged() +{ + m_wizard->setBuildDirectory(m_pc->path()); +} diff --git a/src/plugins/autotoolsprojectmanager/autotoolsopenprojectwizard.h b/src/plugins/autotoolsprojectmanager/autotoolsopenprojectwizard.h new file mode 100644 index 00000000000..5a1056a723e --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsopenprojectwizard.h @@ -0,0 +1,87 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef AUTOTOOLSOPENPROJECTWIZARD_H +#define AUTOTOOLSOPENPROJECTWIZARD_H + +#include <utils/wizard.h> +#include <utils/pathchooser.h> + +namespace AutotoolsProjectManager { +namespace Internal { + +class AutotoolsManager; + +class AutotoolsOpenProjectWizard : public Utils::Wizard +{ + Q_OBJECT +public: + enum PageId + { + BuildPathPageId + }; + + AutotoolsOpenProjectWizard(AutotoolsManager *manager, + const QString &sourceDirectory, + QWidget *parent = 0); + + ~AutotoolsOpenProjectWizard(); + + QString buildDirectory() const; + QString sourceDirectory() const; + void setBuildDirectory(const QString &directory); + AutotoolsManager *autotoolsManager() const; + +private: + void init(); + AutotoolsManager *m_manager; + QString m_buildDirectory; + QString m_sourceDirectory; +}; + +class BuildPathPage : public QWizardPage +{ + Q_OBJECT +public: + explicit BuildPathPage(AutotoolsOpenProjectWizard *wizard); +private slots: + void buildDirectoryChanged(); +private: + AutotoolsOpenProjectWizard *m_wizard; + Utils::PathChooser *m_pc; +}; + +} // namespace Internal +} // namespace AutotoolsProjectManager +#endif //AUTOTOOLSOPENPROJECTWIZARD_H diff --git a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp new file mode 100644 index 00000000000..7a1a514d8ee --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp @@ -0,0 +1,542 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "autotoolsproject.h" +#include "autotoolsprojectconstants.h" +#include "autotoolsmanager.h" +#include "autotoolsprojectnode.h" +#include "autotoolsprojectfile.h" +#include "autotoolsopenprojectwizard.h" +#include "makestep.h" +#include "makefileparserthread.h" + +#include <projectexplorer/abi.h> +#include <projectexplorer/buildenvironmentwidget.h> +#include <projectexplorer/toolchainmanager.h> +#include <projectexplorer/buildconfiguration.h> +#include <projectexplorer/buildsteplist.h> +#include <projectexplorer/projectexplorerconstants.h> +#include <extensionsystem/pluginmanager.h> +#include <cplusplus/ModelManagerInterface.h> +#include <coreplugin/icore.h> +#include <utils/qtcassert.h> + +#include <QtCore/QFileInfo> +#include <QtCore/QTimer> +#include <QtCore/QPointer> +#include <QtGui/QApplication> +#include <QtGui/QCursor> +#include <QtGui/QLabel> +#include <QtGui/QPushButton> +#include <QtGui/QVBoxLayout> + +using namespace AutotoolsProjectManager; +using namespace AutotoolsProjectManager::Internal; +using namespace ProjectExplorer; + +namespace { +const char TOOLCHAIN_KEY[] = "AutotoolsProjectManager.AutotoolsProject.Toolchain"; +} + +AutotoolsProject::AutotoolsProject(AutotoolsManager *manager, const QString &fileName) : + m_manager(manager), + m_fileName(fileName), + m_files(), + m_file(new AutotoolsProjectFile(this, m_fileName)), + m_rootNode(new AutotoolsProjectNode(this, m_file)), + m_fileWatcher(new Utils::FileSystemWatcher(this)), + m_watchedFiles(), + m_makefileParserThread(0), + m_toolChain(0) +{ + setProjectContext(Core::Context(Constants::PROJECT_CONTEXT)); + setProjectLanguage(Core::Context(ProjectExplorer::Constants::LANG_CXX)); + + const QFileInfo fileInfo(m_fileName); + m_projectName = fileInfo.absoluteDir().dirName(); + m_rootNode->setDisplayName(fileInfo.absoluteDir().dirName()); +} + +AutotoolsProject::~AutotoolsProject() +{ + // Although ProjectExplorer::ProjectNode is a QObject, the ctor + // does not allow to specify the parent. Manually setting the + // parent would be possible, but we use the same approach as in the + // other project managers and delete the node manually (TBD). + // + delete m_rootNode; + m_rootNode = 0; + + if (m_makefileParserThread != 0) { + m_makefileParserThread->wait(); + delete m_makefileParserThread; + m_makefileParserThread = 0; + } +} + +void AutotoolsProject::setToolChain(ToolChain *tc) +{ + if (m_toolChain == tc) + return; + + m_toolChain = tc; + + foreach (Target *t, targets()) { + foreach (BuildConfiguration *bc, t->buildConfigurations()) + bc->setToolChain(tc); + } + + emit toolChainChanged(m_toolChain); +} + +ToolChain *AutotoolsProject::toolChain() const +{ + return m_toolChain; +} + +QString AutotoolsProject::displayName() const +{ + return m_projectName; +} + +QString AutotoolsProject::id() const +{ + return QLatin1String(Constants::AUTOTOOLS_PROJECT_ID); +} + +Core::IFile* AutotoolsProject::file() const +{ + return m_file; +} + +ProjectExplorer::IProjectManager* AutotoolsProject::projectManager() const +{ + return m_manager; +} + +AutotoolsTarget *AutotoolsProject::activeTarget() const +{ + return static_cast<AutotoolsTarget *>(Project::activeTarget()); +} + +QList<ProjectExplorer::Project*> AutotoolsProject::dependsOn() +{ + return QList<Project *>(); +} + +QString AutotoolsProject::defaultBuildDirectory() const +{ + return sourceDirectory(); +} + +QList<ProjectExplorer::BuildConfigWidget*> AutotoolsProject::subConfigWidgets() +{ + QList<ProjectExplorer::BuildConfigWidget*> list; + list << new BuildEnvironmentWidget; + return list; +} + +ProjectExplorer::ProjectNode *AutotoolsProject::rootProjectNode() const +{ + return m_rootNode; +} + +QStringList AutotoolsProject::files(FilesMode fileMode) const +{ + Q_UNUSED(fileMode); + return m_files; +} + +QString AutotoolsProject::sourceDirectory() const +{ + return QFileInfo(m_fileName).absolutePath(); +} + +QVariantMap AutotoolsProject::toMap() const +{ + QVariantMap map(Project::toMap()); + map.insert(QLatin1String(TOOLCHAIN_KEY), m_toolChain ? m_toolChain->id() : QString()); + return map; +} + +// This function, is called at the very beginning, to +// restore the settings if there are some stored. +bool AutotoolsProject::fromMap(const QVariantMap &map) +{ + if (!Project::fromMap(map)) + return false; + + // Check if this project was already loaded by checking + // if there already exists a .user file. + bool hasUserFile = activeTarget(); + if (!hasUserFile) { + AutotoolsTargetFactory *factory = + ExtensionSystem::PluginManager::instance()->getObject<AutotoolsTargetFactory>(); + AutotoolsTarget *t = factory->create(this, QLatin1String(Constants::DEFAULT_AUTOTOOLS_TARGET_ID)); + + QTC_ASSERT(t, return false); + QTC_ASSERT(t->activeBuildConfiguration(), return false); + + // Ask the user for where he/she wants to build it. + QFileInfo fileInfo(m_fileName); + const QString defaultBuildDir = fileInfo.absolutePath(); + + QPointer<AutotoolsOpenProjectWizard> wizard = new AutotoolsOpenProjectWizard(m_manager, sourceDirectory()); + if (!wizard->exec() == QDialog::Accepted) + return false; + + AutotoolsBuildConfiguration *bc = + static_cast<AutotoolsBuildConfiguration *>(t->buildConfigurations().at(0)); + if (!wizard->buildDirectory().isEmpty()) + bc->setBuildDirectory(wizard->buildDirectory()); + + addTarget(t); + } + + // Toolchain + QString id = map.value(QLatin1String(TOOLCHAIN_KEY)).toString(); + const ToolChainManager *toolChainManager = ToolChainManager::instance(); + + if (!id.isNull()) { + setToolChain(toolChainManager->findToolChain(id)); + } else { + ProjectExplorer::Abi abi = ProjectExplorer::Abi::hostAbi(); + abi = ProjectExplorer::Abi(abi.architecture(), + abi.os(), + ProjectExplorer::Abi::UnknownFlavor, + abi.binaryFormat(), abi.wordWidth() == 32 ? 32 : 0); + QList<ToolChain *> tcs = toolChainManager->findToolChains(abi); + if (tcs.isEmpty()) + tcs = toolChainManager->toolChains(); + if (!tcs.isEmpty()) + setToolChain(tcs.at(0)); + } + + connect(m_fileWatcher, SIGNAL(fileChanged(QString)), + this, SLOT(onFileChanged(QString))); + + // Load the project tree structure. + loadProjectTree(); + + return true; +} + +void AutotoolsProject::loadProjectTree() +{ + if (m_makefileParserThread != 0) { + // The thread is still busy parsing a previus configuration. + // Wait until the thread has been finished and delete it. + // TODO: Discuss whether blocking is acceptable. + disconnect(m_makefileParserThread, SIGNAL(finished()), + this, SLOT(makefileParsingFinished())); + m_makefileParserThread->wait(); + delete m_makefileParserThread; + m_makefileParserThread = 0; + } + + // Parse the makefile asynchronously in a thread + m_makefileParserThread = new MakefileParserThread(m_fileName); + + connect(m_makefileParserThread, SIGNAL(started()), + this, SLOT(makefileParsingStarted())); + + connect(m_makefileParserThread, SIGNAL(finished()), + this, SLOT(makefileParsingFinished())); + m_makefileParserThread->start(); +} + +void AutotoolsProject::makefileParsingStarted() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); +} + +void AutotoolsProject::makefileParsingFinished() +{ + // The finished() signal is from a previous makefile-parser-thread + // and can be skipped. This can happen, if the thread has emitted the + // finished() signal during the execution of AutotoolsProject::loadProjectTree(). + // In this case the signal is in the message queue already and deleting + // the thread of course does not remove the signal again. + if (sender() != m_makefileParserThread) + return; + + QApplication::restoreOverrideCursor(); + + if (m_makefileParserThread->isCanceled()) { + // The parsing has been cancelled by the user. Don't show any + // project data at all. + m_makefileParserThread->deleteLater(); + m_makefileParserThread = 0; + return; + } + + if (m_makefileParserThread->hasError()) + qWarning("Parsing of makefile contained errors."); + + // Remove file watches for the current project state. + // The file watches will be added again after the parsing. + foreach (const QString& watchedFile, m_watchedFiles) + m_fileWatcher->removeFile(watchedFile); + + m_watchedFiles.clear(); + + // Apply sources to m_files, which are returned at AutotoolsProject::files() + const QFileInfo fileInfo(m_fileName); + const QDir dir = fileInfo.absoluteDir(); + QStringList files = m_makefileParserThread->sources(); + foreach (const QString& file, files) + m_files.append(dir.absoluteFilePath(file)); + + // Watch for changes of Makefile.am files. If a Makefile.am file + // has been changed, the project tree must be reparsed. + const QStringList makefiles = m_makefileParserThread->makefiles(); + foreach (const QString& makefile, makefiles) { + files.append(makefile); + + const QString watchedFile = dir.absoluteFilePath(makefile); + m_fileWatcher->addFile(watchedFile, Utils::FileSystemWatcher::WatchAllChanges); + m_watchedFiles.append(watchedFile); + } + + // Add configure.ac file to project and watch for changes + const QLatin1String configureAc(QLatin1String("configure.ac")); + const QFile configureAcFile(fileInfo.absolutePath() + QChar('/') + configureAc); + if (configureAcFile.exists()) { + files.append(configureAc); + const QString configureAcFilePath = dir.absoluteFilePath(configureAc); + m_fileWatcher->addFile(configureAcFilePath, Utils::FileSystemWatcher::WatchAllChanges); + m_watchedFiles.append(configureAcFilePath); + } + + buildFileNodeTree(dir, files); + updateCppCodeModel(); + + m_makefileParserThread->deleteLater(); + m_makefileParserThread = 0; +} + +void AutotoolsProject::onFileChanged(const QString &file) +{ + Q_UNUSED(file); + loadProjectTree(); +} + +QStringList AutotoolsProject::buildTargets() const +{ + QStringList targets; + targets.append(QLatin1String("all")); + targets.append(QLatin1String("clean")); + return targets; +} + +void AutotoolsProject::buildFileNodeTree(const QDir &directory, + const QStringList &files) +{ + // Get all existing nodes and remember them in a hash table. + // This allows to reuse existing nodes and to remove obsolete + // nodes later. + QHash<QString, ProjectExplorer::Node*> nodeHash; + foreach (ProjectExplorer::Node* node, nodes(m_rootNode)) + nodeHash.insert(node->path(), node); + + // Add the sources to the filenode project tree. Sources + // inside the same directory are grouped into a folder-node. + const QString baseDir = directory.absolutePath(); + + QList<ProjectExplorer::FileNode*> fileNodes; + ProjectExplorer::FolderNode* parentFolder = 0; + ProjectExplorer::FolderNode* oldParentFolder = 0; + + foreach (const QString& file, files) { + if (file.contains(QLatin1String(".moc"))) + continue; + + QString subDir = baseDir + QChar('/') + file; + for (int i = subDir.length() - 1; i >= 0; --i) { + if (subDir.at(i) == QChar('/')) { + subDir = subDir.left(i); + break; + } + } + + // Add folder nodes, that are not already available + oldParentFolder = parentFolder; + parentFolder = 0; + if (nodeHash.contains(subDir)) { + QTC_ASSERT(nodeHash[subDir]->nodeType() == ProjectExplorer::FolderNodeType, return); + parentFolder = static_cast<ProjectExplorer::FolderNode*>(nodeHash[subDir]); + } else { + parentFolder = insertFolderNode(QDir(subDir), nodeHash); + if (parentFolder == 0) { + // No node gets created for the root folder + parentFolder = m_rootNode; + } + } + QTC_ASSERT(parentFolder != 0, return); + if ((oldParentFolder != parentFolder) && !fileNodes.isEmpty()) { + // AutotoolsProjectNode::addFileNodes() is a very expensive operation. It is + // important to collect as much file nodes of the same parent folder as + // possible before invoking it. + m_rootNode->addFileNodes(fileNodes, oldParentFolder); + fileNodes.clear(); + } + + // Add file node + const QString filePath = directory.absoluteFilePath(file); + if (nodeHash.contains(filePath)) { + nodeHash.remove(filePath); + } else { + ProjectExplorer::FileNode* node = + new ProjectExplorer::FileNode(filePath, + ProjectExplorer::ResourceType, + false); + fileNodes.append(node); + } + } + + if (!fileNodes.isEmpty()) + m_rootNode->addFileNodes(fileNodes, parentFolder); + + // Remove unused file nodes and empty folder nodes + QHash<QString, ProjectExplorer::Node*>::const_iterator it = nodeHash.constBegin(); + while (it != nodeHash.constEnd()) { + if ((*it)->nodeType() == ProjectExplorer::FileNodeType) { + ProjectExplorer::FileNode* fileNode = static_cast<ProjectExplorer::FileNode*>(*it); + ProjectExplorer::FolderNode* parent = fileNode->parentFolderNode(); + m_rootNode->removeFileNodes(QList<ProjectExplorer::FileNode*>() << fileNode, parent); + + // Remove all empty parent folders + while (parent->subFolderNodes().isEmpty() && parent->fileNodes().isEmpty()) { + ProjectExplorer::FolderNode* grandParent = parent->parentFolderNode(); + m_rootNode->removeFolderNodes(QList<ProjectExplorer::FolderNode *>() << parent, grandParent); + parent = grandParent; + if (parent == m_rootNode) + break; + } + } + ++it; + } +} + +ProjectExplorer::FolderNode* AutotoolsProject::insertFolderNode(const QDir &nodeDir, + QHash<QString, ProjectExplorer::Node*> &nodes) +{ + const QString nodePath = nodeDir.absolutePath(); + QFileInfo rootInfo(m_rootNode->path()); + const QString rootPath = rootInfo.absolutePath(); + + // Do not create a folder for the root node + if (rootPath == nodePath) + return 0; + + ProjectExplorer::FolderNode* folder = new ProjectExplorer::FolderNode(nodePath); + QDir dir(nodeDir); + folder->setDisplayName(dir.dirName()); + + // Get parent-folder. If it does not exist, create it recursively. + // Take care that the m_rootNode is considered as top folder. + ProjectExplorer::FolderNode* parentFolder = m_rootNode; + if ((rootPath != folder->path()) && dir.cdUp()) { + const QString parentDir = dir.absolutePath(); + if (!nodes.contains(parentDir)) { + ProjectExplorer::FolderNode* insertedFolder = insertFolderNode(parentDir, nodes); + if (insertedFolder != 0) + parentFolder = insertedFolder; + } else { + QTC_ASSERT(nodes[parentDir]->nodeType() == ProjectExplorer::FolderNodeType, return 0); + parentFolder = static_cast<ProjectExplorer::FolderNode*>(nodes[parentDir]); + } + } + + m_rootNode->addFolderNodes(QList<ProjectExplorer::FolderNode*>() << folder, parentFolder); + nodes.insert(nodePath, folder); + + return folder; +} + +QList<ProjectExplorer::Node*> AutotoolsProject::nodes(ProjectExplorer::FolderNode *parent) const +{ + QList<ProjectExplorer::Node*> list; + QTC_ASSERT(parent != 0, return list); + + foreach (ProjectExplorer::FolderNode* folder, parent->subFolderNodes()) { + list.append(nodes(folder)); + list.append(folder); + } + foreach (ProjectExplorer::FileNode* file, parent->fileNodes()) + list.append(file); + + return list; +} + +void AutotoolsProject::updateCppCodeModel() +{ + CPlusPlus::CppModelManagerInterface *modelManager = + CPlusPlus::CppModelManagerInterface::instance(); + + if (!modelManager) + return; + + QStringList allIncludePaths = m_makefileParserThread->includePaths(); + QStringList allFrameworkPaths; + + if (m_toolChain) { + const QList<ProjectExplorer::HeaderPath> allHeaderPaths = m_toolChain->systemHeaderPaths(); + foreach (const ProjectExplorer::HeaderPath &headerPath, allHeaderPaths) { + if (headerPath.kind() == ProjectExplorer::HeaderPath::FrameworkHeaderPath) { + allFrameworkPaths.append(headerPath.path()); + } else { + allIncludePaths.append(headerPath.path()); + } + } + } + + CPlusPlus::CppModelManagerInterface::ProjectInfo pinfo = modelManager->projectInfo(this); + + const bool update = (pinfo.includePaths != allIncludePaths) + || (pinfo.sourceFiles != m_files) + || (pinfo.defines != m_toolChain->predefinedMacros()) + || (pinfo.frameworkPaths != allFrameworkPaths); + if (update) { + pinfo.includePaths = allIncludePaths; + pinfo.sourceFiles = m_files; + if (m_toolChain) + pinfo.defines = m_toolChain->predefinedMacros(); + pinfo.frameworkPaths = allFrameworkPaths; + modelManager->updateProjectInfo(pinfo); + modelManager->updateSourceFiles(pinfo.sourceFiles); + } + + modelManager->updateProjectInfo(pinfo); +} diff --git a/src/plugins/autotoolsprojectmanager/autotoolsproject.h b/src/plugins/autotoolsprojectmanager/autotoolsproject.h new file mode 100644 index 00000000000..e84c56c9923 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsproject.h @@ -0,0 +1,183 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef AUTOTOOLSPROJECT_H +#define AUTOTOOLSPROJECT_H + +#include "autotoolstarget.h" + +#include <coreplugin/editormanager/ieditor.h> +#include <projectexplorer/toolchain.h> +#include <projectexplorer/project.h> +#include <projectexplorer/projectexplorer.h> +#include <projectexplorer/projectnodes.h> +#include <utils/filesystemwatcher.h> + +#include <QtCore/QPointer> +#include <QtCore/QDir> + +namespace ProjectExplorer { +class ToolChain; +} + +namespace AutotoolsProjectManager { +namespace Internal { +class AutotoolsConfigurationFactory; +class AutotoolsProjectFile; +class AutotoolsProjectNode; +class AutotoolsManager; +class MakefileParserThread; +class AutotoolsTarget; + +/** + * @brief Implementation of the ProjectExplorer::Project interface. + * + * Loads the autotools project and embeds it into the QtCreator project tree. + * The class AutotoolsProject is the core of the autotools project plugin. + * It is responsible to parse the Makefile.am files and do trigger project + * updates if a Makefile.am file or a configure.ac file has been changed. + */ +class AutotoolsProject : public ProjectExplorer::Project +{ + Q_OBJECT + +public: + AutotoolsProject(AutotoolsManager *manager, const QString &fileName); + ~AutotoolsProject(); + + QString displayName() const; + QString id() const; + Core::IFile *file() const; + ProjectExplorer::IProjectManager *projectManager() const; + AutotoolsTarget *activeTarget() const; + QList<ProjectExplorer::BuildConfigWidget*> subConfigWidgets(); + ProjectExplorer::ProjectNode *rootProjectNode() const; + QStringList files(FilesMode fileMode) const; + QList<ProjectExplorer::Project*> dependsOn(); + QString defaultBuildDirectory() const; + QString sourceDirectory() const; + QStringList buildTargets() const; + ProjectExplorer::ToolChain *toolChain() const; + void setToolChain(ProjectExplorer::ToolChain *tc); + QVariantMap toMap() const; + +signals: + void toolChainChanged(ProjectExplorer::ToolChain *); + +protected: + bool fromMap(const QVariantMap &map); + +private slots: + /** + * Loads the project tree by parsing the makefiles. + */ + void loadProjectTree(); + + /** + * Is invoked when the makefile parsing by m_makefileParserThread has + * been started. Turns the mouse cursor into a busy cursor. + */ + void makefileParsingStarted(); + + /** + * Is invoked when the makefile parsing by m_makefileParserThread has + * been finished. Adds all sources and files into the project tree and + * takes care listen to file changes for Makefile.am and configure.ac + * files. + */ + void makefileParsingFinished(); + + /** + * Is invoked, if a file of the project tree has been changed by the user. + * If a Makefile.am or a configure.ac file has been changed, the project + * configuration must be updated. + */ + void onFileChanged(const QString &file); + +private: + /** + * Creates folder-nodes and file-nodes for the project tree. + */ + void buildFileNodeTree(const QDir &directory, + const QStringList &files); + + /** + * Helper method for buildFileNodeTree(): Inserts a new folder-node for + * the directory \p nodeDir and inserts it into \p nodes. If no parent + * folder exists, it will be created recursively. + */ + ProjectExplorer::FolderNode* insertFolderNode(const QDir &nodeDir, + QHash<QString, ProjectExplorer::Node*> &nodes); + + /** + * @return All nodes (including sub-folder- and file-nodes) for the given parent folder. + */ + QList<ProjectExplorer::Node*> nodes(ProjectExplorer::FolderNode *parent) const; + + /** + * This function is in charge of the code completion. + */ + void updateCppCodeModel(); + +private: + /// Project manager that has been passed in the constructor + AutotoolsManager *m_manager; + + /// File name of the makefile that has been passed in the constructor + QString m_fileName; + QString m_projectName; + + /// Return value for AutotoolsProject::files() + QStringList m_files; + + /// Return value for AutotoolsProject::file() + AutotoolsProjectFile *m_file; + + /// Return value for AutotoolsProject::rootProjectNode() + AutotoolsProjectNode *m_rootNode; + + /// Watches project files for changes. + Utils::FileSystemWatcher *m_fileWatcher; + QStringList m_watchedFiles; + + /// Responsible for parsing the makefiles asynchronously in a thread + MakefileParserThread *m_makefileParserThread; + + ProjectExplorer::ToolChain *m_toolChain; +}; + +} // namespace Internal +} // namespace AutotoolsProjectManager + +#endif // AUTOTOOLSPROJECT_H diff --git a/src/plugins/autotoolsprojectmanager/autotoolsproject.qrc b/src/plugins/autotoolsprojectmanager/autotoolsproject.qrc new file mode 100644 index 00000000000..514790e9be5 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsproject.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/autotoolsproject" > + <file>AutotoolsProject.mimetypes.xml</file> + </qresource> +</RCC> diff --git a/src/plugins/autotoolsprojectmanager/autotoolsprojectconstants.h b/src/plugins/autotoolsprojectmanager/autotoolsprojectconstants.h new file mode 100644 index 00000000000..cbc442ec601 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsprojectconstants.h @@ -0,0 +1,58 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef AUTOTOOLSPROJECTCONSTANTS_H +#define AUTOTOOLSPROJECTCONSTANTS_H + +namespace AutotoolsProjectManager { +/** + * Collects project constants, that are shared between several classes. + */ +namespace Constants { + const char MAKEFILE_MIMETYPE[] = "text/x-makefile"; + +//BuildConfiguration + const char AUTOTOOLS_BC_ID[] = "AutotoolsProjectManager.AutotoolsBuildConfiguration"; + const char BUILD_DIRECTORY_KEY[] = "AutotoolsProjectManager.AutotoolsBuildConfiguration.BuildDirectory"; + +//Target + const char DEFAULT_AUTOTOOLS_TARGET_ID[] = "AutotoolsProjectManager.DefaultAutotoolsTarget"; + +//Project + const char AUTOTOOLS_PROJECT_ID[] = "AutotoolsProjectManager.AutotoolsProject"; + const char PROJECT_CONTEXT[] = "AutotoolsProject.ProjectContext"; +} // namespace Constants +} // namespace AutotoolsProjectManager + +#endif // AUTOTOOLSPROJECTCONSTANTS_H diff --git a/src/plugins/autotoolsprojectmanager/autotoolsprojectfile.cpp b/src/plugins/autotoolsprojectmanager/autotoolsprojectfile.cpp new file mode 100644 index 00000000000..cdbb2b13ff7 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsprojectfile.cpp @@ -0,0 +1,109 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "autotoolsprojectfile.h" +#include "autotoolsproject.h" +#include "autotoolsprojectconstants.h" + +using namespace AutotoolsProjectManager; +using namespace AutotoolsProjectManager::Internal; + +AutotoolsProjectFile::AutotoolsProjectFile(AutotoolsProject *project, const QString &fileName) : + Core::IFile(project), + m_project(project), + m_fileName(fileName) +{ +} + +AutotoolsProjectFile::~AutotoolsProjectFile() +{ +} + +bool AutotoolsProjectFile::save(QString *errorString, const QString &fileName, bool autoSave) +{ + Q_UNUSED(errorString); + Q_UNUSED(fileName); + Q_UNUSED(autoSave); + + return false; +} + +QString AutotoolsProjectFile::fileName() const +{ + return m_fileName; +} + +QString AutotoolsProjectFile::defaultPath() const +{ + return QString(); +} + +QString AutotoolsProjectFile::suggestedFileName() const +{ + return QString(); +} + +QString AutotoolsProjectFile::mimeType() const +{ + return QLatin1String(Constants::MAKEFILE_MIMETYPE); +} + +bool AutotoolsProjectFile::isModified() const +{ + return false; +} + +bool AutotoolsProjectFile::isReadOnly() const +{ + return true; +} + +bool AutotoolsProjectFile::isSaveAsAllowed() const +{ + return false; +} + +bool AutotoolsProjectFile::reload(QString *errorString, ReloadFlag flag, ChangeType type) +{ + Q_UNUSED(errorString); + Q_UNUSED(flag); + Q_UNUSED(type); + + return false; +} + +void AutotoolsProjectFile::rename(const QString &newName) +{ + Q_UNUSED(newName); +} diff --git a/src/plugins/autotoolsprojectmanager/autotoolsprojectfile.h b/src/plugins/autotoolsprojectmanager/autotoolsprojectfile.h new file mode 100644 index 00000000000..9bf70aa1ad5 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsprojectfile.h @@ -0,0 +1,82 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef AUTOTOOLSPROJECTFILE_H +#define AUTOTOOLSPROJECTFILE_H + +#include <coreplugin/ifile.h> + +namespace AutotoolsProjectManager { +namespace Internal { + +class AutotoolsProject; + +/** + * @brief Implementation of the Core::IFile interface. + * + * Is used in AutotoolsProject and describes the root + * of a project. In the context of autotools the implementation + * is mostly empty, as the modification of a project is + * done by several Makefile.am files and the configure.ac file. + * + * @see AutotoolsProject + */ +class AutotoolsProjectFile : public Core::IFile +{ + Q_OBJECT + +public: + AutotoolsProjectFile(AutotoolsProject *project, const QString &fileName); + ~AutotoolsProjectFile(); + + bool save(QString *errorString, const QString &fileName, bool autoSave); + QString fileName() const; + QString defaultPath() const; + QString suggestedFileName() const; + QString mimeType() const; + bool isModified() const; + bool isReadOnly() const; + bool isSaveAsAllowed() const; + bool reload(QString *errorString, ReloadFlag flag, ChangeType type); + void rename(const QString &newName); + +private: + AutotoolsProject *m_project; + QString m_fileName; +}; + +} // namespace Internal +} // namespace AutotoolsProjectManager + +#endif // AUTOTOOLSPROJECTFILE_H diff --git a/src/plugins/autotoolsprojectmanager/autotoolsprojectmanager.pro b/src/plugins/autotoolsprojectmanager/autotoolsprojectmanager.pro new file mode 100644 index 00000000000..b642847aa7c --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsprojectmanager.pro @@ -0,0 +1,39 @@ +TEMPLATE = lib +TARGET = AutotoolsProjectManager +#PROVIDER = Openismus + +include(../../qtcreatorplugin.pri) +include(autotoolsprojectmanager_dependencies.pri) + +HEADERS = autotoolsprojectplugin.h\ + autotoolsopenprojectwizard.h\ + autotoolsmanager.h\ + autotoolsprojectfile.h\ + autotoolsprojectnode.h\ + autotoolsproject.h\ + autotoolstarget.h\ + autotoolsbuildsettingswidget.h\ + autotoolsbuildconfiguration.h\ + autotoolsprojectconstants.h\ + makestep.h\ + autogenstep.h\ + autoreconfstep.h\ + configurestep.h\ + makefileparserthread.h\ + makefileparser.h +SOURCES = autotoolsprojectplugin.cpp\ + autotoolsopenprojectwizard.cpp\ + autotoolsmanager.cpp\ + autotoolsprojectfile.cpp\ + autotoolsprojectnode.cpp\ + autotoolsproject.cpp\ + autotoolstarget.cpp\ + autotoolsbuildsettingswidget.cpp\ + autotoolsbuildconfiguration.cpp\ + makestep.cpp\ + autogenstep.cpp\ + autoreconfstep.cpp\ + configurestep.cpp\ + makefileparserthread.cpp\ + makefileparser.cpp +RESOURCES += autotoolsproject.qrc diff --git a/src/plugins/autotoolsprojectmanager/autotoolsprojectmanager_dependencies.pri b/src/plugins/autotoolsprojectmanager/autotoolsprojectmanager_dependencies.pri new file mode 100644 index 00000000000..614357cd4d5 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsprojectmanager_dependencies.pri @@ -0,0 +1,3 @@ +include(../../plugins/projectexplorer/projectexplorer.pri) +include(../../plugins/coreplugin/coreplugin.pri) +include(../../plugins/cpptools/cpptools.pri) diff --git a/src/plugins/autotoolsprojectmanager/autotoolsprojectnode.cpp b/src/plugins/autotoolsprojectmanager/autotoolsprojectnode.cpp new file mode 100644 index 00000000000..52feb0368dd --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsprojectnode.cpp @@ -0,0 +1,123 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "autotoolsprojectnode.h" +#include "autotoolsproject.h" + +using namespace AutotoolsProjectManager; +using namespace AutotoolsProjectManager::Internal; + +AutotoolsProjectNode::AutotoolsProjectNode(AutotoolsProject *project, Core::IFile *projectFile) : + ProjectExplorer::ProjectNode(projectFile->fileName()), + m_project(project), + m_projectFile(projectFile) +{ +} + +AutotoolsProjectNode::~AutotoolsProjectNode() +{ +} + +bool AutotoolsProjectNode::hasBuildTargets() const +{ + return true; +} + +QList<ProjectExplorer::ProjectNode::ProjectAction> AutotoolsProjectNode::supportedActions(Node *node) const +{ + Q_UNUSED(node); + return QList<ProjectExplorer::ProjectNode::ProjectAction>(); +} + +bool AutotoolsProjectNode::canAddSubProject(const QString &proFilePath) const +{ + Q_UNUSED(proFilePath) + return false; +} + +bool AutotoolsProjectNode::addSubProjects(const QStringList &proFilePaths) +{ + Q_UNUSED(proFilePaths); + return false; +} + +bool AutotoolsProjectNode::removeSubProjects(const QStringList &proFilePaths) +{ + Q_UNUSED(proFilePaths); + return false; +} + +bool AutotoolsProjectNode::addFiles(const ProjectExplorer::FileType fileType, + const QStringList &filePaths, + QStringList *notAdded) +{ + Q_UNUSED(fileType); + Q_UNUSED(filePaths); + Q_UNUSED(notAdded); + return false; +} + +bool AutotoolsProjectNode::removeFiles(const ProjectExplorer::FileType fileType, + const QStringList &filePaths, + QStringList *notRemoved) +{ + Q_UNUSED(fileType); + Q_UNUSED(filePaths); + Q_UNUSED(notRemoved); + return false; +} + +bool AutotoolsProjectNode::deleteFiles(const ProjectExplorer::FileType fileType, + const QStringList &filePaths) +{ + Q_UNUSED(fileType); + Q_UNUSED(filePaths); + return false; +} + +bool AutotoolsProjectNode::renameFile(const ProjectExplorer::FileType fileType, + const QString &filePath, + const QString &newFilePath) +{ + Q_UNUSED(fileType); + Q_UNUSED(filePath); + Q_UNUSED(newFilePath); + return false; +} + +QList<ProjectExplorer::RunConfiguration *> AutotoolsProjectNode::runConfigurationsFor(Node *node) +{ + Q_UNUSED(node); + return QList<ProjectExplorer::RunConfiguration *>(); +} diff --git a/src/plugins/autotoolsprojectmanager/autotoolsprojectnode.h b/src/plugins/autotoolsprojectmanager/autotoolsprojectnode.h new file mode 100644 index 00000000000..a615ce86bd1 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsprojectnode.h @@ -0,0 +1,93 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef AUTOTOOLSPROJECTNODE_H +#define AUTOTOOLSPROJECTNODE_H + +#include <projectexplorer/projectnodes.h> +#include <coreplugin/ifile.h> + +namespace AutotoolsProjectManager { +namespace Internal { + +class AutotoolsProject; + +/** + * @brief Implementation of the ProjectExplorer::ProjectNode interface. + * + * A project node represents a file or a folder of the project tree. + * No special operations (addFiles(), removeFiles(), renameFile(), ..) + * are offered. + * + * @see AutotoolsProject + */ +class AutotoolsProjectNode : public ProjectExplorer::ProjectNode +{ + Q_OBJECT + +public: + AutotoolsProjectNode(AutotoolsProject *project, Core::IFile *projectFile); + ~AutotoolsProjectNode(); + + bool hasBuildTargets() const; + QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions(Node *node) const; + bool canAddSubProject(const QString &proFilePath) const; + bool addSubProjects(const QStringList &proFilePaths); + bool removeSubProjects(const QStringList &proFilePaths); + bool addFiles(const ProjectExplorer::FileType fileType, + const QStringList &filePaths, + QStringList *notAdded = 0); + bool removeFiles(const ProjectExplorer::FileType fileType, + const QStringList& filePaths, + QStringList *notRemoved = 0); + bool deleteFiles(const ProjectExplorer::FileType fileType, + const QStringList &filePaths); + bool renameFile(const ProjectExplorer::FileType fileType, + const QString &filePath, + const QString &newFilePath); + QList<ProjectExplorer::RunConfiguration *> runConfigurationsFor(Node *node); + +private: + AutotoolsProject *m_project; + Core::IFile *m_projectFile; + + // TODO: AutotoolsProject calls the protected method addFileNodes() from AutotoolsProjectNode. + // Instead of this friend declaration, a public interface might be preferable. + friend class AutotoolsProject; +}; + +} // namespace Internal +} // namespace AutotoolsProjectManager + +#endif // AUTOTOOLSPROJECTNODE_H diff --git a/src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.cpp b/src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.cpp new file mode 100644 index 00000000000..2e53addffcd --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.cpp @@ -0,0 +1,85 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "autotoolsprojectplugin.h" +#include "autotoolsmanager.h" +#include "autotoolstarget.h" +#include "autotoolsbuildconfiguration.h" +#include "makestep.h" +#include "autogenstep.h" +#include "autoreconfstep.h" +#include "configurestep.h" +#include "autotoolsprojectconstants.h" + +#include <coreplugin/icore.h> +#include <coreplugin/mimedatabase.h> + +#include <QtCore/QStringList> +#include <QtCore/QtPlugin> + +using namespace AutotoolsProjectManager::Internal; + +AutotoolsProjectPlugin::AutotoolsProjectPlugin() +{ +} + +AutotoolsProjectPlugin::~AutotoolsProjectPlugin() +{ +} + +void AutotoolsProjectPlugin::extensionsInitialized() +{ +} + +bool AutotoolsProjectPlugin::initialize(const QStringList &arguments, + QString *errorString) +{ + Q_UNUSED(arguments); + + Core::ICore *core = Core::ICore::instance(); + if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":autotoolsproject/AutotoolsProject.mimetypes.xml"), errorString)) + return false; + + addAutoReleasedObject(new AutotoolsTargetFactory); + addAutoReleasedObject(new AutotoolsBuildConfigurationFactory); + addAutoReleasedObject(new MakeStepFactory()); + addAutoReleasedObject(new AutogenStepFactory()); + addAutoReleasedObject(new ConfigureStepFactory()); + addAutoReleasedObject(new AutoreconfStepFactory()); + addAutoReleasedObject(new AutotoolsManager()); + + return true; +} + +Q_EXPORT_PLUGIN(AutotoolsProjectPlugin) diff --git a/src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.h b/src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.h new file mode 100644 index 00000000000..2b5e15c4350 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.h @@ -0,0 +1,84 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef AUTOTOOLSPROJECTMANAGER_H +#define AUTOTOOLSPROJECTMANAGER_H + +#include <extensionsystem/iplugin.h> + +namespace AutotoolsProjectManager { +namespace Internal { + +/** + * @brief Implementation of the ExtensionsSystem::IPlugin interface. + * + * The plugin creates the following components: + * + * - AutotoolsManager: Will manage the new autotools project and + * tell QtCreator for which MIME types the autotools project should + * be instantiated. + * + * - MakeStepFactory: This factory is used to create make steps. + * + * - AutogenStepFactory: This factory is used to create autogen steps. + * + * - AutoreconfStepFactory: This factory is used to create autoreconf + * steps. + * + * - ConfigureStepFactory: This factory is used to create configure steps. + * + * - MakefileEditorFactory: Provides a specialized editor with automatic + * syntax highlighting for Makefile.am files. + * + * - AutotoolsTargetFactory: Our current target is desktop. + * + * - AutotoolsBuildConfigurationFactory: Creates build configurations that + * contain the steps (make, autogen, autoreconf or configure) that will + * be executed in the build process) + */ + +class AutotoolsProjectPlugin : public ExtensionSystem::IPlugin +{ +public: + AutotoolsProjectPlugin(); + ~AutotoolsProjectPlugin(); + + void extensionsInitialized(); + bool initialize(const QStringList &arguments, QString *errorString); +}; + +} // namespace Internal +} // namespace AutotoolsProjectManager + +#endif // AUTOTOOLSPROJECTMANAGER_H diff --git a/src/plugins/autotoolsprojectmanager/autotoolstarget.cpp b/src/plugins/autotoolsprojectmanager/autotoolstarget.cpp new file mode 100644 index 00000000000..1c32bec871a --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolstarget.cpp @@ -0,0 +1,186 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "autotoolstarget.h" +#include "autotoolsproject.h" +#include "autotoolsprojectconstants.h" +#include "autotoolsbuildsettingswidget.h" +#include "autotoolsbuildconfiguration.h" +#include "makestep.h" +#include "autogenstep.h" +#include "autoreconfstep.h" +#include "configurestep.h" + +#include <projectexplorer/customexecutablerunconfiguration.h> +#include <projectexplorer/buildsteplist.h> +#include <projectexplorer/projectexplorerconstants.h> +#include <extensionsystem/pluginmanager.h> + +#include <QtGui/QApplication> +#include <QtGui/QStyle> + +using namespace AutotoolsProjectManager; +using namespace AutotoolsProjectManager::Internal; + +namespace { + +QString displayNameForId(const QString &id) { + if (id == QLatin1String(Constants::DEFAULT_AUTOTOOLS_TARGET_ID)) + return QApplication::translate("AutotoolsProjectManager::Internal::AutotoolsTarget", + "Desktop", "Autotools Default target display name"); + return QString(); +} +} + +////////////////////////// +// AutotoolsTarget class +////////////////////////// + +AutotoolsTarget::AutotoolsTarget(AutotoolsProject *parent) : + ProjectExplorer::Target(parent, QLatin1String(Constants::DEFAULT_AUTOTOOLS_TARGET_ID)), + m_buildConfigurationFactory(new AutotoolsBuildConfigurationFactory(this)) +{ + setDefaultDisplayName(displayNameForId(id())); + setIcon(qApp->style()->standardIcon(QStyle::SP_ComputerIcon)); +} + +AutotoolsTarget::~AutotoolsTarget() +{ +} + +ProjectExplorer::BuildConfigWidget *AutotoolsTarget::createConfigWidget() +{ + return new AutotoolsBuildSettingsWidget(this); +} + + +AutotoolsProject *AutotoolsTarget::autotoolsProject() const +{ + return static_cast<AutotoolsProject *>(project()); +} + +AutotoolsBuildConfiguration *AutotoolsTarget::activeBuildConfiguration() const +{ + return static_cast<AutotoolsBuildConfiguration *>(Target::activeBuildConfiguration()); +} + +AutotoolsBuildConfigurationFactory *AutotoolsTarget::buildConfigurationFactory() const +{ + return m_buildConfigurationFactory; +} + +QString AutotoolsTarget::defaultBuildDirectory() const +{ + return autotoolsProject()->defaultBuildDirectory(); +} + +bool AutotoolsTarget::fromMap(const QVariantMap &map) +{ + return Target::fromMap(map); +} + +///////////////////////////////// +// AutotoolsTargetFactory class +///////////////////////////////// +AutotoolsTargetFactory::AutotoolsTargetFactory(QObject *parent) : + ITargetFactory(parent) +{ +} + +AutotoolsTargetFactory::~AutotoolsTargetFactory() +{ +} + +bool AutotoolsTargetFactory::supportsTargetId(const QString &id) const +{ + return id == QLatin1String(Constants::DEFAULT_AUTOTOOLS_TARGET_ID); +} + +QStringList AutotoolsTargetFactory::supportedTargetIds(ProjectExplorer::Project *parent) const +{ + if (!qobject_cast<AutotoolsProject *>(parent)) + return QStringList(); + return QStringList() << QLatin1String(Constants::DEFAULT_AUTOTOOLS_TARGET_ID); +} + +QString AutotoolsTargetFactory::displayNameForId(const QString &id) const +{ + return ::displayNameForId(id); +} + +bool AutotoolsTargetFactory::canCreate(ProjectExplorer::Project *parent, const QString &id) const +{ + if (!qobject_cast<AutotoolsProject *>(parent)) + return false; + return id == QLatin1String(Constants::DEFAULT_AUTOTOOLS_TARGET_ID); +} + +AutotoolsTarget *AutotoolsTargetFactory::create(ProjectExplorer::Project *parent, const QString &id) +{ + if (!canCreate(parent, id)) + return 0; + + AutotoolsProject *project(static_cast<AutotoolsProject *>(parent)); + AutotoolsTarget *t = new AutotoolsTarget(project); + + // Add default build configuration: + AutotoolsBuildConfigurationFactory *bcf = ExtensionSystem::PluginManager::instance()->getObject<AutotoolsBuildConfigurationFactory>(); + AutotoolsBuildConfiguration *bc = bcf->createDefaultConfiguration(t); + bc->setDisplayName("Default Build"); + + t->addBuildConfiguration(bc); + t->addDeployConfiguration(t->createDeployConfiguration(ProjectExplorer::Constants::DEFAULT_DEPLOYCONFIGURATION_ID)); + // User needs to choose where the executable file is. + // TODO: Parse the file in *Anjuta style* to be able to add custom RunConfigurations. + t->addRunConfiguration(new ProjectExplorer::CustomExecutableRunConfiguration(t)); + + return t; +} + +bool AutotoolsTargetFactory::canRestore(ProjectExplorer::Project *parent, const QVariantMap &map) const +{ + return canCreate(parent, ProjectExplorer::idFromMap(map)); +} + +AutotoolsTarget *AutotoolsTargetFactory::restore(ProjectExplorer::Project *parent, const QVariantMap &map) +{ + if (!canRestore(parent, map)) + return 0; + AutotoolsProject *autotoolsproject(static_cast<AutotoolsProject *>(parent)); + AutotoolsTarget *target = new AutotoolsTarget(autotoolsproject); + if (target->fromMap(map)) + return target; + delete target; + return 0; +} diff --git a/src/plugins/autotoolsprojectmanager/autotoolstarget.h b/src/plugins/autotoolsprojectmanager/autotoolstarget.h new file mode 100644 index 00000000000..6ac9481af8a --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/autotoolstarget.h @@ -0,0 +1,101 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef AUTOTOOLSTARGET_H +#define AUTOTOOLSTARGET_H + +#include "autotoolsbuildconfiguration.h" + +#include <projectexplorer/target.h> + +namespace AutotoolsProjectManager { +namespace Internal { + +class AutotoolsTargetFactory; +class AutotoolsBuildConfiguration; +class AutotoolsBuildConfigurationFactory; +class AutotoolsProject; + +/////////////////////////// +//// AutotoolsTarget class +/////////////////////////// +class AutotoolsTarget : public ProjectExplorer::Target +{ + Q_OBJECT + friend class AutotoolsTargetFactory; + +public: + explicit AutotoolsTarget(AutotoolsProject *parent); + ~AutotoolsTarget(); + + ProjectExplorer::BuildConfigWidget *createConfigWidget(); + AutotoolsProject *autotoolsProject() const; + AutotoolsBuildConfigurationFactory *buildConfigurationFactory() const; + AutotoolsBuildConfiguration *activeBuildConfiguration() const; + QString defaultBuildDirectory() const; + +protected: + bool fromMap(const QVariantMap &map); + +private: + AutotoolsBuildConfigurationFactory *m_buildConfigurationFactory; +}; + + +////////////////////////////////// +//// AutotoolsTargetFactory class +////////////////////////////////// +class AutotoolsTargetFactory : public ProjectExplorer::ITargetFactory +{ + Q_OBJECT + +public: + explicit AutotoolsTargetFactory(QObject *parent = 0); + ~AutotoolsTargetFactory(); + + bool supportsTargetId(const QString &id) const; + + QStringList supportedTargetIds(ProjectExplorer::Project *parent) const; + QString displayNameForId(const QString &id) const; + + bool canCreate(ProjectExplorer::Project *parent, const QString &id) const; + AutotoolsTarget *create(ProjectExplorer::Project *parent, const QString &id); + bool canRestore(ProjectExplorer::Project *parent, const QVariantMap &map) const; + AutotoolsTarget *restore(ProjectExplorer::Project *parent, const QVariantMap &map); +}; + +} // namespace Internal +} // namespace AutotoolsProjectManager + +#endif // AUTOTOOLSTARGET_H diff --git a/src/plugins/autotoolsprojectmanager/configurestep.cpp b/src/plugins/autotoolsprojectmanager/configurestep.cpp new file mode 100644 index 00000000000..80037bb0a6e --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/configurestep.cpp @@ -0,0 +1,303 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "configurestep.h" +#include "autotoolsproject.h" +#include "autotoolstarget.h" +#include "autotoolsbuildconfiguration.h" +#include "autotoolsprojectconstants.h" + +#include <projectexplorer/buildsteplist.h> +#include <projectexplorer/toolchain.h> +#include <projectexplorer/gnumakeparser.h> +#include <projectexplorer/projectexplorer.h> +#include <projectexplorer/projectexplorerconstants.h> +#include <utils/qtcprocess.h> + +#include <QtCore/QVariantMap> +#include <QtCore/QDateTime> +#include <QtGui/QLineEdit> +#include <QtGui/QFormLayout> + +using namespace AutotoolsProjectManager; +using namespace AutotoolsProjectManager::Internal; +using namespace ProjectExplorer; + +namespace { +const char CONFIGURE_ADDITIONAL_ARGUMENTS_KEY[] = "AutotoolsProjectManager.ConfigureStep.AdditionalArguments"; +const char CONFIGURE_STEP_ID[] = "AutotoolsProjectManager.ConfigureStep"; +} + +//////////////////////////////// +// ConfigureStepFactory Class +//////////////////////////////// +ConfigureStepFactory::ConfigureStepFactory(QObject *parent) : + ProjectExplorer::IBuildStepFactory(parent) +{ +} + +ConfigureStepFactory::~ConfigureStepFactory() +{ +} + +QStringList ConfigureStepFactory::availableCreationIds(BuildStepList *parent) const +{ + if (parent->target()->project()->id() == QLatin1String(Constants::AUTOTOOLS_PROJECT_ID)) + return QStringList() << QLatin1String(CONFIGURE_STEP_ID); + return QStringList(); +} + +QString ConfigureStepFactory::displayNameForId(const QString &id) const +{ + if (id == QLatin1String(CONFIGURE_STEP_ID)) + return tr("Configure", "Display name for AutotoolsProjectManager::ConfigureStep id."); + return QString(); +} + +bool ConfigureStepFactory::canCreate(BuildStepList *parent, const QString &id) const +{ + if (parent->target()->project()->id() != QLatin1String(Constants::AUTOTOOLS_PROJECT_ID)) + return false; + + if (parent->id() != ProjectExplorer::Constants::BUILDSTEPS_BUILD) + return false; + + return QLatin1String(CONFIGURE_STEP_ID) == id; +} + +BuildStep *ConfigureStepFactory::create(BuildStepList *parent, const QString &id) +{ + if (!canCreate(parent, id)) + return 0; + return new ConfigureStep(parent); +} + +bool ConfigureStepFactory::canClone(BuildStepList *parent, BuildStep *source) const +{ + return canCreate(parent, source->id()); +} + +BuildStep *ConfigureStepFactory::clone(BuildStepList *parent, BuildStep *source) +{ + if (!canClone(parent, source)) + return 0; + return new ConfigureStep(parent, static_cast<ConfigureStep *>(source)); +} + +bool ConfigureStepFactory::canRestore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map) const +{ + QString id(ProjectExplorer::idFromMap(map)); + return canCreate(parent, id); +} + +BuildStep *ConfigureStepFactory::restore(BuildStepList *parent, const QVariantMap &map) +{ + if (!canRestore(parent, map)) + return 0; + ConfigureStep *bs = new ConfigureStep(parent); + if (bs->fromMap(map)) + return bs; + delete bs; + return 0; +} + +//////////////////////// +// ConfigureStep class +//////////////////////// +ConfigureStep::ConfigureStep(ProjectExplorer::BuildStepList* bsl) : + AbstractProcessStep(bsl, QLatin1String(CONFIGURE_STEP_ID)), + m_runConfigure(false) +{ + ctor(); +} + +ConfigureStep::ConfigureStep(ProjectExplorer::BuildStepList *bsl, const QString &id) : + AbstractProcessStep(bsl, id) +{ + ctor(); +} + +ConfigureStep::ConfigureStep(ProjectExplorer::BuildStepList *bsl, ConfigureStep *bs) : + AbstractProcessStep(bsl, bs), + m_additionalArguments(bs->additionalArguments()) +{ + ctor(); +} + +void ConfigureStep::ctor() +{ + setDefaultDisplayName(tr("Configure")); +} + +ConfigureStep::~ConfigureStep() +{ +} + +AutotoolsBuildConfiguration *ConfigureStep::autotoolsBuildConfiguration() const +{ + return static_cast<AutotoolsBuildConfiguration *>(buildConfiguration()); +} + +bool ConfigureStep::init() +{ + AutotoolsBuildConfiguration *bc = autotoolsBuildConfiguration(); + + setEnabled(true); + + ProcessParameters *pp = processParameters(); + pp->setMacroExpander(bc->macroExpander()); + pp->setEnvironment(bc->environment()); + pp->setWorkingDirectory(bc->buildDirectory()); + pp->setCommand("configure"); + pp->setArguments(additionalArguments()); + + return AbstractProcessStep::init(); +} + +void ConfigureStep::run(QFutureInterface<bool>& interface) +{ + AutotoolsBuildConfiguration *bc = autotoolsBuildConfiguration(); + + //Check wether we need to run configure + const QFileInfo configureInfo(bc->buildDirectory() + QLatin1String("/configure")); + const QFileInfo configStatusInfo(bc->buildDirectory() + QLatin1String("/config.status")); + + if (!configStatusInfo.exists() + || configStatusInfo.lastModified() < configureInfo.lastModified()) { + m_runConfigure = true; + } + + if (!m_runConfigure) { + emit addOutput(tr("Configuration unchanged, skipping configure step."), BuildStep::MessageOutput); + interface.reportResult(true); + return; + } + + m_runConfigure = false; + AbstractProcessStep::run(interface); +} + +ProjectExplorer::BuildStepConfigWidget* ConfigureStep::createConfigWidget() +{ + return new ConfigureStepConfigWidget(this); +} + +bool ConfigureStep::immutable() const +{ + return false; +} + +void ConfigureStep::setAdditionalArguments(const QString &list) +{ + if (list == m_additionalArguments) + return; + + m_additionalArguments = list; + m_runConfigure = true; + + emit additionalArgumentsChanged(list); +} + +QString ConfigureStep::additionalArguments() const +{ + return m_additionalArguments; +} + +QVariantMap ConfigureStep::toMap() const +{ + QVariantMap map(AbstractProcessStep::toMap()); + + map.insert(QLatin1String(CONFIGURE_ADDITIONAL_ARGUMENTS_KEY), m_additionalArguments); + return map; +} + +bool ConfigureStep::fromMap(const QVariantMap &map) +{ + m_additionalArguments = map.value(QLatin1String(CONFIGURE_ADDITIONAL_ARGUMENTS_KEY)).toString(); + + return BuildStep::fromMap(map); +} + +///////////////////////////////////// +// ConfigureStepConfigWidget class +///////////////////////////////////// +ConfigureStepConfigWidget::ConfigureStepConfigWidget(ConfigureStep *configureStep) : + m_configureStep(configureStep), + m_summaryText(), + m_additionalArguments(0) +{ + QFormLayout *fl = new QFormLayout(this); + fl->setMargin(0); + fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); + setLayout(fl); + + m_additionalArguments = new QLineEdit(this); + fl->addRow(tr("Arguments:"), m_additionalArguments); + m_additionalArguments->setText(m_configureStep->additionalArguments()); + + updateDetails(); + + connect(m_additionalArguments, SIGNAL(textChanged(QString)), + configureStep, SLOT(setAdditionalArguments(QString))); + connect(configureStep, SIGNAL(additionalArgumentsChanged(QString)), + this, SLOT(updateDetails())); +} + +ConfigureStepConfigWidget::~ConfigureStepConfigWidget() +{ +} + +QString ConfigureStepConfigWidget::displayName() const +{ + return tr("Configure", "AutotoolsProjectManager::ConfigureStepConfigWidget display name."); +} + +QString ConfigureStepConfigWidget::summaryText() const +{ + return m_summaryText; +} + +void ConfigureStepConfigWidget::updateDetails() +{ + AutotoolsBuildConfiguration *bc = m_configureStep->autotoolsBuildConfiguration(); + + ProcessParameters param; + param.setMacroExpander(bc->macroExpander()); + param.setEnvironment(bc->environment()); + param.setWorkingDirectory(bc->buildDirectory()); + param.setCommand("configure"); + param.setArguments(m_configureStep->additionalArguments()); + m_summaryText = param.summary(displayName()); + emit updateSummary(); +} diff --git a/src/plugins/autotoolsprojectmanager/configurestep.h b/src/plugins/autotoolsprojectmanager/configurestep.h new file mode 100644 index 00000000000..ffc5aea17ca --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/configurestep.h @@ -0,0 +1,162 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef CONFIGURESTEP_H +#define CONFIGURESTEP_H + +#include <projectexplorer/abstractprocessstep.h> + +QT_BEGIN_NAMESPACE +class QLineEdit; +QT_END_NAMESPACE + +namespace AutotoolsProjectManager { +namespace Internal { + +class AutotoolsProject; +class AutotoolsBuildConfiguration; +class ConfigureStepConfigWidget; + +////////////////////////////////// +// ConfigureStepFactory Class +////////////////////////////////// +/** + * @brief Implementation of the ProjectExplorer::IBuildStepFactory interface. + * + * The factory is used to create instances of ConfigureStep. + */ +class ConfigureStepFactory : public ProjectExplorer::IBuildStepFactory +{ + Q_OBJECT + +public: + ConfigureStepFactory(QObject *parent = 0); + ~ConfigureStepFactory(); + + QStringList availableCreationIds(ProjectExplorer::BuildStepList *bc) const; + QString displayNameForId(const QString &id) const; + + bool canCreate(ProjectExplorer::BuildStepList *parent, const QString &id) const; + ProjectExplorer::BuildStep *create(ProjectExplorer::BuildStepList *parent, const QString &id); + bool canClone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source) const; + ProjectExplorer::BuildStep *clone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source); + bool canRestore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map) const; + ProjectExplorer::BuildStep *restore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map); +}; + +////////////////////////// +//// ConfigureStep class +////////////////////////// +///** +// * @brief Implementation of the ProjectExplorer::AbstractProcessStep interface. +// * +// * A configure step can be configured by selecting the "Projects" button of Qt +// * Creator (in the left hand side menu) and under "Build Settings". +// * +// * It is possible for the user to specify custom arguments. The corresponding +// * configuration widget is created by MakeStep::createConfigWidget and is +// * represented by an instance of the class MakeStepConfigWidget. +// */ +class ConfigureStep : public ProjectExplorer::AbstractProcessStep +{ + Q_OBJECT + friend class ConfigureStepFactory; + friend class ConfigureStepConfigWidget; + +public: + + ConfigureStep(ProjectExplorer::BuildStepList *bsl); + ~ConfigureStep(); + + AutotoolsBuildConfiguration *autotoolsBuildConfiguration() const; + bool init(); + void run(QFutureInterface<bool> &interface); + ProjectExplorer::BuildStepConfigWidget *createConfigWidget(); + bool immutable() const; + QString additionalArguments() const; + QVariantMap toMap() const; + +public slots: + void setAdditionalArguments(const QString &list); + +signals: + void additionalArgumentsChanged(const QString &); + +protected: + ConfigureStep(ProjectExplorer::BuildStepList *bsl, ConfigureStep *bs); + ConfigureStep(ProjectExplorer::BuildStepList *bsl, const QString &id); + + bool fromMap(const QVariantMap &map); + +private: + void ctor(); + + QString m_additionalArguments; + bool m_runConfigure; +}; + +///////////////////////////////////// +// ConfigureStepConfigWidget class +///////////////////////////////////// +/** + * @brief Implementation of the ProjectExplorer::BuildStepConfigWidget interface. + * + * Allows to configure a configure step in the GUI. + */ +class ConfigureStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget +{ + Q_OBJECT + +public: + ConfigureStepConfigWidget(ConfigureStep *configureStep); + ~ConfigureStepConfigWidget(); + + QString displayName() const; + QString summaryText() const; + + +private slots: + void updateDetails(); + +private: + ConfigureStep *m_configureStep; + QString m_summaryText; + QLineEdit *m_additionalArguments; +}; + +} // namespace Internal +} // namespace AutotoolsProjectManager + +#endif // CONFIGURESTEP_H + diff --git a/src/plugins/autotoolsprojectmanager/makefileparser.cpp b/src/plugins/autotoolsprojectmanager/makefileparser.cpp new file mode 100644 index 00000000000..a9db927ee48 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/makefileparser.cpp @@ -0,0 +1,454 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "makefileparser.h" + +#include <utils/qtcassert.h> + +#include <QtCore/QFile> +#include <QtCore/QFileInfoList> +#include <QtCore/QMutexLocker> + +using namespace AutotoolsProjectManager::Internal; + +MakefileParser::MakefileParser(const QString &makefile) : + QObject(), + m_success(false), + m_cancel(false), + m_mutex(), + m_makefile(makefile), + m_executable(), + m_sources(), + m_makefiles(), + m_includePaths(), + m_line(), + m_textStream() +{ +} + +MakefileParser::~MakefileParser() +{ +} + +bool MakefileParser::parse() +{ + m_mutex.lock(); + m_cancel = false; + m_mutex.unlock(), + + m_success = true; + m_executable.clear(); + m_sources.clear(); + m_makefiles.clear(); + + QFile *file = new QFile(m_makefile); + if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) + return false; + + QFileInfo info(m_makefile); + m_makefiles.append(info.fileName()); + + emit status(tr("Parsing %1 in directory %2").arg(info.fileName()).arg(info.absolutePath())); + + m_textStream.setDevice(file); + + do { + m_line = m_textStream.readLine(); + switch (topTarget()) { + case AmDefaultSourceExt: parseDefaultSourceExtensions(); break; + case BinPrograms: parseBinPrograms(); break; + case BuiltSources: break; // TODO: Add to m_sources? + case Sources: parseSources(); break; + case SubDirs: parseSubDirs(); break; + case Undefined: + default: break; + } + } while (!m_line.isNull()); + + parseIncludePaths(); + + return m_success; +} + +QStringList MakefileParser::sources() const +{ + return m_sources; +} + +QStringList MakefileParser::makefiles() const +{ + return m_makefiles; +} + +QString MakefileParser::executable() const +{ + return m_executable; +} + +QStringList MakefileParser::includePaths() const +{ + return m_includePaths; +} + +void MakefileParser::cancel() +{ + QMutexLocker locker(&m_mutex); + m_cancel = true; +} + +bool MakefileParser::isCanceled() const +{ + QMutexLocker locker(&m_mutex); + return m_cancel; +} + +MakefileParser::TopTarget MakefileParser::topTarget() const +{ + TopTarget topTarget = Undefined; + + const QString line = m_line.simplified(); + if (!line.isEmpty() && !line.startsWith(QChar('#'))) { + // TODO: Check how many fixed strings like AM_DEFAULT_SOURCE_EXT will + // be needed vs. variable strings like _SOURCES. Dependend on this a + // more clever way than this (expensive) if-cascading might be done. + if (line.startsWith(QLatin1String("AM_DEFAULT_SOURCE_EXT ="))) + topTarget = AmDefaultSourceExt; + else if (line.startsWith(QLatin1String("bin_PROGRAMS ="))) + topTarget = BinPrograms; + else if (line.startsWith(QLatin1String("BUILT_SOURCES ="))) + topTarget = BuiltSources; + else if (line.contains(QLatin1String("SUBDIRS ="))) + topTarget = SubDirs; + else if (line.contains(QLatin1String("_SOURCES ="))) + topTarget = Sources; + } + + return topTarget; +} + +void MakefileParser::parseBinPrograms() +{ + QTC_ASSERT(m_line.contains(QLatin1String("bin_PROGRAMS")), return); + const QStringList binPrograms = targetValues(); + + // TODO: are multiple values possible? + if (binPrograms.size() == 1) { + QFileInfo info(binPrograms.first()); + m_executable = info.fileName(); + } +} + +void MakefileParser::parseSources() +{ + QTC_ASSERT(m_line.contains(QLatin1String("_SOURCES")), return); + + bool hasVariables = false; + m_sources.append(targetValues(&hasVariables)); + + // Skip parsing of Makefile.am for getting the sub directories, + // as variables have been used. As fallback all sources will be added. + if (hasVariables) + addAllSources(); + + // Duplicates might be possible in combination with 'AM_DEFAULT_SOURCE_EXT =' + m_sources.removeDuplicates(); + + // TODO: Definitions like "SOURCES = ../src.cpp" are ignored currently. + // This case must be handled correctly in MakefileParser::parseSubDirs(), + // where the current sub directory must be shortened. + QStringList::iterator it = m_sources.begin(); + while (it != m_sources.end()) { + if ((*it).startsWith(QLatin1String(".."))) + it = m_sources.erase(it); + else + ++it; + } +} + +void MakefileParser::parseDefaultSourceExtensions() +{ + QTC_ASSERT(m_line.contains(QLatin1String("AM_DEFAULT_SOURCE_EXT")), return); + const QStringList extensions = targetValues(); + if (extensions.isEmpty()) { + m_success = false; + return; + } + + QFileInfo info(m_makefile); + const QString dirName = info.absolutePath(); + m_sources.append(directorySources(dirName, extensions)); + + // Duplicates might be possible in combination with '_SOURCES =' + m_sources.removeDuplicates(); +} + +void MakefileParser::parseSubDirs() +{ + QTC_ASSERT(m_line.contains(QLatin1String("SUBDIRS")), return); + if (isCanceled()) { + m_success = false; + return; + } + + QFileInfo info(m_makefile); + const QString path = info.absolutePath(); + const QString makefileName = info.fileName(); + + bool hasVariables = false; + QStringList subDirs = targetValues(&hasVariables); + if (hasVariables) { + // Skip parsing of Makefile.am for getting the sub directories, + // as variables have been used. As fallback all sources will be added. + addAllSources(); + return; + } + + // If the SUBDIRS values contain a '.' or a variable like $(test), + // all the sub directories of the current folder must get parsed. + bool hasDotSubDir = false; + QStringList::iterator it = subDirs.begin(); + while (it != subDirs.end()) { + // Erase all entries that represent a '.' + if ((*it) == QChar('.')) { + hasDotSubDir = true; + it = subDirs.erase(it); + } else { + ++it; + } + } + if (hasDotSubDir) { + // Add all sub directories of the current folder + QDir dir(path); + dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); + foreach (const QFileInfo& info, dir.entryInfoList()) { + subDirs.append(info.fileName()); + } + } + subDirs.removeDuplicates(); + + // Delegate the parsing of all sub directories to a local + // makefile parser and merge the results + foreach (const QString& subDir, subDirs) { + const QChar slash('/'); + const QString subDirMakefile = path + slash + subDir + + slash + makefileName; + + // Parse sub directory + QFile *file = new QFile(subDirMakefile); + + // Don't try to parse a file, that might not exist (e. g. + // if SUBDIRS specifies a 'po' directory). + if (!file->exists()) + continue; + + MakefileParser parser(subDirMakefile); + connect(&parser, SIGNAL(status(QString)), this, SIGNAL(status(QString))); + const bool success = parser.parse(); + + // Don't return, try to parse as many sub directories + // as possible + if (!success) + m_success = false; + + m_makefiles.append(subDir + slash + makefileName); + + // Append the sources of the sub directory to the + // current sources + foreach (const QString& source, parser.sources()) + m_sources.append(subDir + slash + source); + + // Duplicates might be possible in combination with several + // "..._SUBDIRS" targets + m_makefiles.removeDuplicates(); + m_sources.removeDuplicates(); + } + + if (subDirs.isEmpty()) + m_success = false; +} + +QStringList MakefileParser::directorySources(const QString &directory, + const QStringList &extensions) +{ + if (isCanceled()) { + m_success = false; + return QStringList(); + } + + emit status(tr("Parsing directory %1").arg(directory)); + + QStringList list; // return value + + QDir dir(directory); + dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); + + const QFileInfoList infos = dir.entryInfoList(); + foreach (const QFileInfo& info, infos) { + if (info.isDir()) { + // Append recursively sources from the sub directory + const QStringList subDirSources = directorySources(info.absoluteFilePath(), + extensions); + const QString dirPath = info.fileName(); + foreach (const QString& subDirSource, subDirSources) + list.append(dirPath + QChar('/') + subDirSource); + } else { + // Check whether the file matches to an extension + foreach (const QString& extension, extensions) { + if (info.fileName().endsWith(extension)) { + list.append(info.fileName()); + appendHeader(list, dir, info.baseName()); + break; + } + } + } + } + + return list; +} + +QStringList MakefileParser::targetValues(bool *hasVariables) +{ + QStringList values; + if (hasVariables != 0) + *hasVariables = false; + + const int index = m_line.indexOf(QChar('=')); + if (index < 0) { + m_success = false; + return QStringList(); + } + + m_line.remove(0, index + 1); // remove the 'target = ' prefix + + bool endReached = false; + do { + m_line = m_line.simplified(); + + // Get all values of a line separated by spaces. + // Values representing a variable like $(value) get + // removed currently. + QStringList lineValues = m_line.split(QChar(' ')); + QStringList::iterator it = lineValues.begin(); + while (it != lineValues.end()) { + if ((*it).startsWith(QLatin1String("$("))) { + it = lineValues.erase(it); + if (hasVariables != 0) + *hasVariables = true; + } else { + ++it; + } + } + + endReached = lineValues.isEmpty(); + if (!endReached) { + const QChar backSlash('\\'); + QString last = lineValues.last(); + if (last.endsWith(backSlash)) { + // The last value contains a backslash. Remove the + // backslash and replace the last value. + lineValues.pop_back(); + last.remove(backSlash); + if (!last.isEmpty()) + lineValues.push_back(last); + + values.append(lineValues); + m_line = m_textStream.readLine(); + endReached = m_line.isNull(); + } else { + values.append(lineValues); + endReached = true; + } + } + } while (!endReached); + + return values; +} + +void MakefileParser::appendHeader(QStringList &list, const QDir &dir, const QString &fileName) +{ + const char *const headerExtensions[] = { ".h", ".hh", ".hg", ".hxx", ".hpp", 0 }; + int i = 0; + while (headerExtensions[i] != 0) { + const QString headerFile = fileName + QLatin1String(headerExtensions[i]); + QFileInfo fileInfo(dir, headerFile); + if (fileInfo.exists()) + list.append(headerFile); + ++i; + } +} + +void MakefileParser::addAllSources() +{ + QStringList extensions; + extensions << QLatin1String(".c") + << QLatin1String(".cpp") + << QLatin1String(".cc") + << QLatin1String(".cxx") + << QLatin1String(".ccg"); + QFileInfo info(m_makefile); + m_sources.append(directorySources(info.absolutePath(), extensions)); + m_sources.removeDuplicates(); +} + +void MakefileParser::parseIncludePaths() +{ + QFileInfo info(m_makefile); + const QString dirName = info.absolutePath(); + + QFile *file = new QFile(dirName + QLatin1String("/Makefile")); + if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) + return; + + // TODO: The parsing is done very poor. Comments are ignored and targets + // are ignored too. Whether it is worth to improve this, depends on whether + // we want to parse the generated Makefile at all or whether we want to + // improve the Makefile.am parsing to be aware of variables. + QTextStream textStream(file); + QString line; + do { + line = textStream.readLine(); + QStringList terms = line.split(QLatin1Char(' '), QString::SkipEmptyParts); + foreach (const QString &term, terms) { + if (term.startsWith(QLatin1String("-I"))) { + QString includePath = term.right(term.length() - 2); // remove the "-I" + if (includePath == QLatin1String(".")) + includePath = dirName; + if (!includePath.isEmpty()) + m_includePaths += includePath; + } + } + } while (!line.isNull()); + + m_includePaths.removeDuplicates(); +} diff --git a/src/plugins/autotoolsprojectmanager/makefileparser.h b/src/plugins/autotoolsprojectmanager/makefileparser.h new file mode 100644 index 00000000000..ede6bfe45cd --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/makefileparser.h @@ -0,0 +1,231 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef MAKEFILEPARSER_H +#define MAKEFILEPARSER_H + +#include <QtCore/QMutex> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QTextStream> +#include <QtCore/QObject> +#include <QtCore/QDir> +#include <QtCore/QFileInfo> + +namespace AutotoolsProjectManager { +namespace Internal { + +/** + * @brief Parses the autotools makefile Makefile.am. + * + * The parser returns the sources, makefiles and executable. + * Variables like $(test) are not evaluated. If such a variable + * is part of a SOURCES target, a fallback will be done and all + * sub directories get parsed for C- and C++ files. + */ +class MakefileParser : public QObject +{ + Q_OBJECT + +public: + /** + * @param makefile Filename including path of the autotools + * makefile that should be parsed. + */ + MakefileParser(const QString &makefile); + ~MakefileParser(); + + /** + * Parses the makefile. Must be invoked at least once, otherwise + * the getter methods of MakefileParser will return empty values. + * @return True, if the parsing was successful. If false is returned, + * the makefile could not be opened. + */ + bool parse(); + + /** + * @return List of sources that are set for the _SOURCES target. + * Sources in sub directorties contain the sub directory as + * prefix. + */ + QStringList sources() const; + + /** + * @return List of Makefile.am files from the current directory and + * all sub directories. The values for sub directories contain + * the sub directory as prefix. + */ + QStringList makefiles() const; + + /** + * @return File name of the executable. + */ + QString executable() const; + + /** + * @return List of include paths. Should be invoked, after the signal + * finished() has been emitted. + */ + QStringList includePaths() const; + + /** + * Cancels the parsing. Calling this method only makes sense, if the + * parser runs in a different thread than the caller of this method. + * The method is thread-safe. + */ + void cancel(); + + /** + * @return True, if the parser has been cancelled by MakefileParser::cancel(). + * The method is thread-safe. + */ + bool isCanceled() const; + +signals: + /** + * Is emitted periodically during parsing the Makefile.am files + * and the sub directories. \p status provides a translated + * string, that can be shown to indicate the current state + * of the parsing. + */ + void status(const QString &status); + +private: + enum TopTarget { + Undefined, + AmDefaultSourceExt, + BinPrograms, + BuiltSources, + Sources, + SubDirs + }; + + TopTarget topTarget() const; + + /** + * Parses the bin_PROGRAM target and stores it in m_executable. + */ + void parseBinPrograms(); + + /** + * Parses all values from a _SOURCE target and appends them to + * the m_sources list. + */ + void parseSources(); + + /** + * Parses all sub directories for files having the extension + * specified by 'AM_DEFAULT_SOURCE_EXT ='. The result will be + * append to the m_sources list. Corresponding header files + * will automatically be attached too. + */ + void parseDefaultSourceExtensions(); + + /** + * Parses all sub directories specified by the SUBDIRS target and + * adds the found sources to the m_sources list. The found makefiles + * get added to the m_makefiles list. + */ + void parseSubDirs(); + + /** + * Helper method for parseDefaultExtensions(). Returns recursively all sources + * inside the directory \p directory that match with the extension \p extension. + */ + QStringList directorySources(const QString &directory, + const QStringList &extensions); + + /** + * Helper method for all parse-methods. Returns each value of a target as string in + * the stringlist. The current line m_line is used as starting point and increased + * if the current line ends with a \. + * + * Example: For the text + * \code + * my_SOURCES = a.cpp\ + * b.cpp c.cpp\ + * d.cpp + * \endcode + * the string list contains all 4 *.cpp files. m_line is positioned to d.cpp afterwards. + * Variables like $(test) are skipped and not part of the return value. + * + * @param hasVariables Optional output parameter. Is set to true, if the target values + * contained a variable like $(test). Note that all variables are not + * part of the return value, as they cannot get interpreted currently. + */ + QStringList targetValues(bool *hasVariables = 0); + + /** + * Adds recursively all sources of the current folder to m_sources and removes + * all duplicates. The Makefile.am is not parsed, only the folders and files are + * handled. This method should only be called, if the sources parsing in the Makefile.am + * failed because variables (e.g. $(test)) have been used. + */ + void addAllSources(); + + /** + * Adds all include paths to m_includePaths. TODO: Currently this is done + * by parsing the generated Makefile. It might be more efficient and reliable + * to parse the Makefile.am instead. + */ + void parseIncludePaths(); + + /** + * Helper method for MakefileParser::directorySources(). Appends the name of the headerfile + * to \p list, if the header could be found in the directory specified by \p dir. + * The headerfile base name is defined by \p fileName. + */ + static void appendHeader(QStringList &list, const QDir &dir, const QString &fileName); + +private: + bool m_success; ///< Return value for MakefileParser::parse(). + + bool m_cancel; ///< True, if the parsing should be cancelled. + mutable QMutex m_mutex; ///< Mutex to protect m_cancel. + + QString m_makefile; ///< Filename of the makefile + QString m_executable; ///< Return value for MakefileParser::executable() + QStringList m_sources; ///< Return value for MakefileParser::sources() + QStringList m_makefiles; ///< Return value for MakefileParser::makefiles() + QStringList m_includePaths; ///< Return value for MakefileParser::includePaths() + + QString m_line; ///< Current line of the makefile + QTextStream m_textStream; ///< Textstream that represents the makefile +}; + +} // namespace Internal +} // namespace AutotoolsProjectManager + +#endif // MAKEFILEPARSER_H + diff --git a/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp b/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp new file mode 100644 index 00000000000..eee5c718dc9 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp @@ -0,0 +1,112 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "makefileparserthread.h" + +#include <QtCore/QMutexLocker> + +using namespace AutotoolsProjectManager::Internal; + +MakefileParserThread::MakefileParserThread(const QString &makefile) : + QThread(), + m_parser(makefile), + m_mutex(), + m_hasError(false), + m_executable(), + m_sources(), + m_makefiles(), + m_includePaths() +{ + connect(&m_parser, SIGNAL(status(QString)), this, SIGNAL(status(QString))); +} + +MakefileParserThread::~MakefileParserThread() +{ +} + +QStringList MakefileParserThread::sources() const +{ + QMutexLocker locker(&m_mutex); + return m_sources; +} + +QStringList MakefileParserThread::makefiles() const +{ + QMutexLocker locker(&m_mutex); + return m_makefiles; +} + +QString MakefileParserThread::executable() const +{ + QMutexLocker locker(&m_mutex); + return m_executable; +} + +QStringList MakefileParserThread::includePaths() const +{ + QMutexLocker locker(&m_mutex); + return m_includePaths; +} + +bool MakefileParserThread::hasError() const +{ + QMutexLocker locker(&m_mutex); + return m_hasError; +} + +bool MakefileParserThread::isCanceled() const +{ + // MakefileParser::isCanceled() is thread-safe + return m_parser.isCanceled(); +} + +void MakefileParserThread::cancel() +{ + m_parser.cancel(); +} + +void MakefileParserThread::run() +{ + const bool success = m_parser.parse(); + + // Important: Start locking the mutex _after_ the parsing has been finished, as + // this prevents long locks if the caller reads a value before the signal + // finished() has been emitted. + QMutexLocker locker(&m_mutex); + m_hasError = !success; + m_executable = m_parser.executable(); + m_sources = m_parser.sources(); + m_makefiles = m_parser.makefiles(); + m_includePaths = m_parser.includePaths(); +} diff --git a/src/plugins/autotoolsprojectmanager/makefileparserthread.h b/src/plugins/autotoolsprojectmanager/makefileparserthread.h new file mode 100644 index 00000000000..4815dc392b7 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/makefileparserthread.h @@ -0,0 +1,136 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef MAKEFILEPARSERTHREAD_H +#define MAKEFILEPARSERTHREAD_H + +#include <makefileparser.h> + +#include <QtCore/QMutex> +#include <QtCore/QString> +#include <QtCore/QThread> + +namespace AutotoolsProjectManager { +namespace Internal { + +/** + * @brief Executes the makefile parser in the thread. + * + * After the finished() signal has been emitted, the makefile + * parser output can be read by sources(), makefiles() and executable(). + * A parsing error can be checked by hasError(). + */ +class MakefileParserThread : public QThread +{ + Q_OBJECT + +public: + MakefileParserThread(const QString &makefile); + ~MakefileParserThread(); + + /** @see QThread::run() */ + void run(); + + /** + * @return List of sources that are set for the _SOURCES target. + * Sources in sub directorties contain the sub directory as + * prefix. Should be invoked, after the signal finished() + * has been emitted. + */ + QStringList sources() const; + + /** + * @return List of Makefile.am files from the current directory and + * all sub directories. The values for sub directories contain + * the sub directory as prefix. Should be invoked, after the + * signal finished() has been emitted. + */ + QStringList makefiles() const; + + /** + * @return File name of the executable. Should be invoked, after the + * signal finished() has been emitted. + */ + QString executable() const; + + /** + * @return List of include paths. Should be invoked, after the signal + * finished() has been emitted. + */ + QStringList includePaths() const; + + /** + * @return True, if an error occured during the parsing. Should be invoked, + * after the signal finished() has been emitted. + */ + bool hasError() const; + + /** + * @return True, if the the has been cancelled by MakefileParserThread::cancel(). + */ + bool isCanceled() const; + +public slots: + /** + * Cancels the parsing of the makefile. MakefileParser::hasError() will + * return true in this case. + */ + void cancel(); + +signals: + /** + * Is emitted periodically during parsing the Makefile.am files + * and the sub directories. \p status provides a translated + * string, that can be shown to indicate the current state + * of the parsing. + */ + void status(const QString &status); + +private: + MakefileParser m_parser; ///< Is not accessible outside the thread + + mutable QMutex m_mutex; + bool m_hasError; ///< Return value for MakefileParserThread::hasError() + QString m_executable; ///< Return value for MakefileParserThread::executable() + QStringList m_sources; ///< Return value for MakefileParserThread::sources() + QStringList m_makefiles; ///< Return value for MakefileParserThread::makefiles() + QStringList m_includePaths; ///< Return value for MakefileParserThread::includePaths() +}; + +} // namespace Internal +} // namespace AutotoolsProjectManager + +#endif // MAKEFILEPARSERTHREAD_H + + diff --git a/src/plugins/autotoolsprojectmanager/makestep.cpp b/src/plugins/autotoolsprojectmanager/makestep.cpp new file mode 100644 index 00000000000..2cafcc82d36 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/makestep.cpp @@ -0,0 +1,326 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "makestep.h" +#include "autotoolsproject.h" +#include "autotoolsprojectconstants.h" +#include "autotoolsbuildconfiguration.h" +#include "autotoolstarget.h" + +#include <projectexplorer/buildsteplist.h> +#include <projectexplorer/toolchain.h> +#include <projectexplorer/gnumakeparser.h> +#include <projectexplorer/projectexplorer.h> +#include <projectexplorer/projectexplorerconstants.h> +#include <utils/qtcprocess.h> + +#include <QtCore/QVariantMap> +#include <QtGui/QLineEdit> +#include <QtGui/QFormLayout> + +using namespace AutotoolsProjectManager; +using namespace AutotoolsProjectManager::Internal; +using namespace ProjectExplorer; + +namespace { +const char MAKE_STEP_ID[] = "AutotoolsProjectManager.MakeStep"; +const char CLEAN_KEY[] = "AutotoolsProjectManager.MakeStep.Clean"; +const char BUILD_TARGETS_KEY[] = "AutotoolsProjectManager.MakeStep.BuildTargets"; +const char MAKE_STEP_ADDITIONAL_ARGUMENTS_KEY[] = "AutotoolsProjectManager.MakeStep.AdditionalArguments"; +} + +////////////////////////// +// MakeStepFactory class +////////////////////////// +MakeStepFactory::MakeStepFactory(QObject *parent) : + ProjectExplorer::IBuildStepFactory(parent) +{ +} + +MakeStepFactory::~MakeStepFactory() +{ +} + +QStringList MakeStepFactory::availableCreationIds(BuildStepList *parent) const +{ + if (parent->target()->project()->id() == QLatin1String(Constants::AUTOTOOLS_PROJECT_ID)) + return QStringList() << QLatin1String(MAKE_STEP_ID); + return QStringList(); +} + +QString MakeStepFactory::displayNameForId(const QString &id) const +{ + if (id == QLatin1String(MAKE_STEP_ID)) + return tr("Make", "Display name for AutotoolsProjectManager::MakeStep id."); + return QString(); +} + +bool MakeStepFactory::canCreate(BuildStepList *parent, const QString &id) const +{ + if (parent->target()->project()->id() != QLatin1String(Constants::AUTOTOOLS_PROJECT_ID)) + return false; + + if (parent->id() != ProjectExplorer::Constants::BUILDSTEPS_BUILD) + return false; + + return QLatin1String(MAKE_STEP_ID) == id; +} + +BuildStep *MakeStepFactory::create(BuildStepList *parent, const QString &id) +{ + if (!canCreate(parent, id)) + return 0; + return new MakeStep(parent); +} + +bool MakeStepFactory::canClone(BuildStepList *parent, BuildStep *source) const +{ + return canCreate(parent, source->id()); +} + +BuildStep *MakeStepFactory::clone(BuildStepList *parent, BuildStep *source) +{ + if (!canClone(parent, source)) + return 0; + return new MakeStep(parent, static_cast<MakeStep *>(source)); +} + +bool MakeStepFactory::canRestore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map) const +{ + QString id(ProjectExplorer::idFromMap(map)); + return canCreate(parent, id); +} + +BuildStep *MakeStepFactory::restore(BuildStepList *parent, const QVariantMap &map) +{ + if (!canRestore(parent, map)) + return 0; + MakeStep *bs = new MakeStep(parent); + if (bs->fromMap(map)) + return bs; + delete bs; + return 0; +} + +///////////////////// +// MakeStep class +///////////////////// +MakeStep::MakeStep(ProjectExplorer::BuildStepList* bsl) : + AbstractProcessStep(bsl, QLatin1String(MAKE_STEP_ID)), + m_clean(false) +{ + ctor(); +} + +MakeStep::MakeStep(ProjectExplorer::BuildStepList *bsl, const QString &id) : + AbstractProcessStep(bsl, id), + m_clean(false) +{ + ctor(); +} + +MakeStep::MakeStep(ProjectExplorer::BuildStepList *bsl, MakeStep *bs) : + AbstractProcessStep(bsl, bs), + m_buildTargets(bs->m_buildTargets), + m_additionalArguments(bs->additionalArguments()), + m_clean(bs->m_clean) +{ + ctor(); +} + +void MakeStep::ctor() +{ + setDefaultDisplayName(tr("Make")); +} + +MakeStep::~MakeStep() +{ +} + +AutotoolsBuildConfiguration *MakeStep::autotoolsBuildConfiguration() const +{ + return static_cast<AutotoolsBuildConfiguration *>(buildConfiguration()); +} + +void MakeStep::setClean(bool clean) +{ + m_clean = clean; +} + +bool MakeStep::init() +{ + AutotoolsBuildConfiguration *bc = autotoolsBuildConfiguration(); + + QString arguments = Utils::QtcProcess::joinArgs(m_buildTargets); + Utils::QtcProcess::addArgs(&arguments, additionalArguments()); + + setEnabled(true); + setIgnoreReturnValue(m_clean); + + ProcessParameters *pp = processParameters(); + pp->setMacroExpander(bc->macroExpander()); + pp->setEnvironment(bc->environment()); + pp->setWorkingDirectory(bc->buildDirectory()); + pp->setCommand(bc->toolChain()->makeCommand()); + pp->setArguments(arguments); + + setOutputParser(new ProjectExplorer::GnuMakeParser()); + if (bc->autotoolsTarget()->autotoolsProject()->toolChain()) + appendOutputParser(bc->autotoolsTarget()->autotoolsProject()->toolChain()->outputParser()); + outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory()); + + return AbstractProcessStep::init(); +} + +void MakeStep::run(QFutureInterface<bool> &interface) +{ + AbstractProcessStep::run(interface); +} + +ProjectExplorer::BuildStepConfigWidget* MakeStep::createConfigWidget() +{ + return new MakeStepConfigWidget(this); +} + +bool MakeStep::immutable() const +{ + return false; +} + +void MakeStep::setBuildTarget(const QString &target, bool on) +{ + QStringList old = m_buildTargets; + if (on && !old.contains(target)) + old << target; + else if (!on && old.contains(target)) + old.removeOne(target); + + m_buildTargets = old; +} + +void MakeStep::setAdditionalArguments(const QString &list) +{ + if (list == m_additionalArguments) + return; + + m_additionalArguments = list; + + emit additionalArgumentsChanged(list); +} + +QString MakeStep::additionalArguments() const +{ + return m_additionalArguments; +} + +QVariantMap MakeStep::toMap() const +{ + QVariantMap map(AbstractProcessStep::toMap()); + + map.insert(QLatin1String(BUILD_TARGETS_KEY), m_buildTargets); + map.insert(QLatin1String(MAKE_STEP_ADDITIONAL_ARGUMENTS_KEY), m_additionalArguments); + map.insert(QLatin1String(CLEAN_KEY), m_clean); + return map; +} + +bool MakeStep::fromMap(const QVariantMap &map) +{ + m_buildTargets = map.value(QLatin1String(BUILD_TARGETS_KEY)).toStringList(); + m_additionalArguments = map.value(QLatin1String(MAKE_STEP_ADDITIONAL_ARGUMENTS_KEY)).toString(); + m_clean = map.value(QLatin1String(CLEAN_KEY)).toBool(); + + return BuildStep::fromMap(map); +} + +/////////////////////////////// +// MakeStepConfigWidget class +/////////////////////////////// +MakeStepConfigWidget::MakeStepConfigWidget(MakeStep *makeStep) : + m_makeStep(makeStep), + m_summaryText(), + m_additionalArguments(0) +{ + QFormLayout *fl = new QFormLayout(this); + fl->setMargin(0); + fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); + setLayout(fl); + + m_additionalArguments = new QLineEdit(this); + fl->addRow(tr("Arguments:"), m_additionalArguments); + m_additionalArguments->setText(m_makeStep->additionalArguments()); + + updateDetails(); + + connect(m_additionalArguments, SIGNAL(textChanged(QString)), + makeStep, SLOT(setAdditionalArguments(QString))); + connect(makeStep, SIGNAL(additionalArgumentsChanged(QString)), + this, SLOT(updateDetails())); +} + +MakeStepConfigWidget::~MakeStepConfigWidget() +{ +} + +QString MakeStepConfigWidget::displayName() const +{ + return tr("Make", "AutotoolsProjectManager::MakeStepConfigWidget display name."); +} + +QString MakeStepConfigWidget::summaryText() const +{ + return m_summaryText; +} + +void MakeStepConfigWidget::updateDetails() +{ + AutotoolsBuildConfiguration *bc = m_makeStep->autotoolsBuildConfiguration(); + ProjectExplorer::ToolChain *tc = bc->toolChain(); + + if (tc) { + QString arguments = Utils::QtcProcess::joinArgs(m_makeStep->m_buildTargets); + Utils::QtcProcess::addArgs(&arguments, m_makeStep->additionalArguments()); + + ProcessParameters param; + param.setMacroExpander(bc->macroExpander()); + param.setEnvironment(bc->environment()); + param.setWorkingDirectory(bc->buildDirectory()); + param.setCommand(tc->makeCommand()); + param.setArguments(arguments); + m_summaryText = param.summary(displayName()); + } else { + m_summaryText = tr("<b>Unknown tool chain</b>"); + } + + emit updateSummary(); +} diff --git a/src/plugins/autotoolsprojectmanager/makestep.h b/src/plugins/autotoolsprojectmanager/makestep.h new file mode 100644 index 00000000000..af849ff8709 --- /dev/null +++ b/src/plugins/autotoolsprojectmanager/makestep.h @@ -0,0 +1,163 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010-2011 Openismus GmbH. +** Authors: Peter Penz (ppenz@openismus.com) +** Patricia Santana Cruz (patriciasantanacruz@gmail.com) +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef MAKESTEP_H +#define MAKESTEP_H + +#include <projectexplorer/abstractprocessstep.h> + +QT_BEGIN_NAMESPACE +class QLineEdit; +QT_END_NAMESPACE + +namespace AutotoolsProjectManager { +namespace Internal { + +class AutotoolsProject; +class AutotoolsBuildConfiguration; +class MakeStep; + +/////////////////////////// +// MakeStepFactory class +/////////////////////////// +/** + * @brief Implementation of the ProjectExplorer::IBuildStepFactory interface. + * + * The factory is used to create instances of MakeStep. + */ +class MakeStepFactory : public ProjectExplorer::IBuildStepFactory +{ + Q_OBJECT + +public: + MakeStepFactory(QObject *parent = 0); + ~MakeStepFactory(); + + QStringList availableCreationIds(ProjectExplorer::BuildStepList *bc) const; + QString displayNameForId(const QString &id) const; + + bool canCreate(ProjectExplorer::BuildStepList *parent, const QString &id) const; + ProjectExplorer::BuildStep *create(ProjectExplorer::BuildStepList *parent, const QString &id); + bool canClone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source) const; + ProjectExplorer::BuildStep *clone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source); + bool canRestore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map) const; + ProjectExplorer::BuildStep *restore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map); +}; + +///////////////////// +// MakeStep class +///////////////////// +/** + * @brief Implementation of the ProjectExplorer::AbstractProcessStep interface. + * + * A make step can be configured by selecting the "Projects" button of Qt Creator + * (in the left hand side menu) and under "Build Settings". + * + * It is possible for the user to specify custom arguments. The corresponding + * configuration widget is created by MakeStep::createConfigWidget and is + * represented by an instance of the class MakeStepConfigWidget. + */ +class MakeStep : public ProjectExplorer::AbstractProcessStep +{ + Q_OBJECT + friend class MakeStepFactory; + friend class MakeStepConfigWidget; + +public: + + MakeStep(ProjectExplorer::BuildStepList *bsl); + ~MakeStep(); + + AutotoolsBuildConfiguration *autotoolsBuildConfiguration() const; + bool init(); + void run(QFutureInterface<bool> &interface); + ProjectExplorer::BuildStepConfigWidget *createConfigWidget(); + void setClean(bool clean); + bool immutable() const; + void setBuildTarget(const QString &target, bool on); + QString additionalArguments() const; + QVariantMap toMap() const; + +public slots: + void setAdditionalArguments(const QString &list); + +signals: + void additionalArgumentsChanged(const QString &); + +protected: + MakeStep(ProjectExplorer::BuildStepList *bsl, MakeStep *bs); + MakeStep(ProjectExplorer::BuildStepList *bsl, const QString &id); + + bool fromMap(const QVariantMap &map); + +private: + void ctor(); + + QStringList m_buildTargets; + QString m_additionalArguments; + bool m_clean; +}; + +/////////////////////////////// +// MakeStepConfigWidget class +/////////////////////////////// +/** + * @brief Implementation of the ProjectExplorer::BuildStepConfigWidget interface. + * + * Allows to configure a make step in the GUI. + */ +class MakeStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget +{ + Q_OBJECT + +public: + MakeStepConfigWidget(MakeStep *makeStep); + ~MakeStepConfigWidget(); + + QString displayName() const; + QString summaryText() const; + +private slots: + void updateDetails(); + +private: + MakeStep *m_makeStep; + QString m_summaryText; + QLineEdit *m_additionalArguments; +}; + +} // namespace Internal +} // namespace AutotoolsProjectManager + +#endif // MAKESTEP_H diff --git a/src/plugins/genericprojectmanager/genericprojectwizard.cpp b/src/plugins/genericprojectmanager/genericprojectwizard.cpp index 00b961d8fe4..dfabed3b36b 100644 --- a/src/plugins/genericprojectmanager/genericprojectwizard.cpp +++ b/src/plugins/genericprojectmanager/genericprojectwizard.cpp @@ -129,7 +129,7 @@ Core::BaseFileWizardParameters GenericProjectWizard::parameters() } parameters.setDisplayName(tr("Import Existing Project")); parameters.setId(QLatin1String("Z.Makefile")); - parameters.setDescription(tr("Imports existing projects that do not use qmake or CMake. " + parameters.setDescription(tr("Imports existing projects that do not use qmake, CMake or Autotools. " "This allows you to use Qt Creator as a code editor.")); parameters.setCategory(QLatin1String(ProjectExplorer::Constants::IMPORT_WIZARD_CATEGORY)); parameters.setDisplayCategory(QLatin1String(ProjectExplorer::Constants::IMPORT_WIZARD_CATEGORY_DISPLAY)); diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index b1eff599b78..419f1f2f5db 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -25,6 +25,7 @@ SUBDIRS = plugin_coreplugin \ plugin_help \ plugin_cpaster \ plugin_cmakeprojectmanager \ + plugin_autotoolsprojectmanager \ plugin_fakevim \ plugin_designer \ plugin_resourceeditor \ @@ -216,6 +217,11 @@ plugin_cmakeprojectmanager.depends = plugin_texteditor plugin_cmakeprojectmanager.depends += plugin_projectexplorer plugin_cmakeprojectmanager.depends += plugin_cpptools +plugin_autotoolsprojectmanager.subdir = autotoolsprojectmanager +plugin_autotoolsprojectmanager.depends = plugin_projectexplorer +plugin_autotoolsprojectmanager.depends += plugin_coreplugin +plugin_autotoolsprojectmanager.depends += plugin_cpptools + plugin_genericprojectmanager.subdir = genericprojectmanager plugin_genericprojectmanager.depends = plugin_texteditor plugin_genericprojectmanager.depends += plugin_projectexplorer -- GitLab